shell脚本之路

shell分类

  • Bourne Shell(/usr/bin/sh或/bin/sh)

  • Bourne Again Shell(/bin/bash)

  • C Shell(/usr/bin/csh)

  • K Shell(/usr/bin/ksh)

  • Shell for Root(/sbin/sh)

    注意:

    1. 在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。
    2. #!告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序

shell脚本的编写

  1. 创建shell文本
#  查看linux系统中shell位置:cat /etc/shells ||  cat /etc/shell 
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh   
/usr/bin/bash //常用
/usr/sbin/nologin
/bin/tcsh
/bin/csh //c语言风格
# 创建shell脚本文件
vi/vim fileName.sh
  1. shell脚本书写格式
#!/bin/bash
echo "Hello World !"

注: shell中变量赋值没有空格,输出变量时,格式为echo $variableName
  1. shell脚本赋予执行权限
chmod +x ./test.sh  #使脚本具有执行权限
  1. 执行命令
# 方法一
./test.sh 或 .test.sh  #执行脚本
# 方法二(适用于其他路径执行shell脚本)
/bin/bash /study/shell_study/my_first.sh
# 方法三(在当前进程中运行 Shell 脚本)
source filename 或者 . filename
或
bash /study/shell_study/my_second.sh 
注:
# 在新进程中运行 Shell 脚本
bash test.sh
# 在当前进程中运行 Shell 脚本
. ./test.sh
备注:
    1.作为解释器参数这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名, 如:
        /bin/sh test.sh
        /bin/php test.php
    2.循环linux下的目录时,注意引号"'",使用"`"。
    3.注意变了输出 $name 或者 ${name}
    
    linux中查看当前进程pid命令: echo $$

5.shell命令

  • readyonly,只读模式。
#!/bin/bash
myUrl="http://www.google.com"
readonly myUrl
  • unset,删除变量。注:unset 命令不能删除只读变量。
#!/bin/sh
myUrl="http://www.runoob.com"
unset myUrl
echo $myUrl
  • 获取字符串长度
#!/bin/sh
string="http://www.runoob.com"
echo ${#string}
  • 截取字符串
#!/bin/bash
string="http://www.runoob.com"
echo ${string:1:4} #截取字符串1-4位

-   字符串截取总结
        格式                                	说明
${string: start :length}	从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。
${string: start}	        从 string 字符串的左边第 start 个字符开始截取,直到最后。
${string: 0-start :length}	从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
${string: 0-start}      	从 string 字符串的右边第 start 个字符开始截取,直到最后。
${string#*chars}        	从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string##*chars}	        从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string%*chars}	        从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
${string%%*chars}	        从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
  • 查找子字符串
string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

注:
    1.截取字符串与调用命令分别:${string:start:length},$('command');
    2.从右边开始截取${string:0-start:length}
    3.从指定字符串开始截取 ${string#*start_string}
    4.直到最后一个指定字符(子字符串)再匹配结束 ${string##*start_string}
  • 字符串拼接
eg:
    #! /bin/bash
    str1='china'
    str2='广东'
    str3='广州'
    str4='白云区'
    str5='番禺区'
    str6='腾讯大厦'
    
    str_new1=$str1$str2
    str_new2="$str2 $str3"
    str_new3=$str4":"$str5
    str_new4="$str5:$str6"
    str_new5="${str1} test: ${str2} index.html"
    
    echo $str_new1
    echo $str_new2
    echo $str_new3
    echo $str_new4
    echo $str_new5


结果:
    [root@localhost shell_study]# bash string_merge.sh 
    china广东
    广东 广州
    白云区:番禺区
    番禺区:腾讯大厦
    china test: 广东 index.html

  • 数组定义
数组名=(值1 值2 ... 值n)
 如:
    array_name=(value0 value1 value2 value3)
        或者
    array_name=(
    value0
    value1
    value2
    value3
    )
还可以单独定义数组的各个分量:
    array_name[0]=value0
    array_name[1]=value1
    array_name[n]=valuen

读取

读取数组元素值的一般格式:
${数组名[下标]}

使用 @ 或者 * 符号可以获取数组中的所有元素
echo ${array_name[@]}
  • 获取数组长度
# 取得数组元素的个数
length=${#array_name[@]}
或者
length=${#array_name[*]}

# 取得数组单个元素的长度
length=${#array_name[n]}
  • 拼接数组
array_new=(${arr[@]} ${array[*]})

eg:
    arr=(1 2 'test')
    array=('zhang' 'li' 'wang')
    arr_new=(${arr[*]} ${array[@]})
    #获取拼接的数组
    echo ${arr_new[*]}
结果:
    [root@localhost shell_study]# bash arr_merge.sh 
    1 2 test zhang li wang


  • 删除数组
删除数组中的元素
unset array_new[index]

删除全部元素
unset array_new

eg:
    #! /bin/bash
    arr_del=('test' 'new' 'hello')
    unset arr_del[0]
    echo ${arr_del[*]}
    unset arr_del
    echo ${arr_del[@]}
结果:
    [root@localhost shell_study]# bash arr_del.sh 
    new hello

  • 注释

单行注释

#--------------------------------------------
# 这是一个注释
# author:t_fengyun
# site:www.51about.com
# slogan:个人博客
#--------------------------------------------
##### 用户配置区 开始 #####
#
#
# 这里可以添加脚本描述信息
# 
#
##### 用户配置区 结束  #####

多行注释

:<

代码多行备注

代码中多行代码需要注释断点并进行测试,要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
  • 参数的传递

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……

#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。如"$*“用「”」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ ∗ 相 同 , 但 是 使 用 时 加 引 号 , 并 在 引 号 中 返 回 每 个 参 数 。 如 " *相同,但是使用时加引号,并在引号中返回每个参数。如" 使"@“用「”」括起来的情况、以"$1" “ 2 " … " 2" … " 2""n” 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash

val=`expr 2 + 2`
echo "两数之和为 : $val"

a=10
b=20

val=`expr $a + $b`
echo "a + b : $val"
运算符 说明 举例
+ 加法 expr $a + $b 结果为 30。
- 减法 expr $a - $b 结果为 -10。
* 乘法 expr $a \* $b 结果为 200。
/ 除法 expr $b / $a 结果为 2。
% 取余 expr $b % $a 结果为 0。
= 赋值 a=$b 将把变量 b 的值赋给 a。
== 相等。用于比较两个数字,相同则返回 true。 [ $a == $b ] 返回 false。
!= 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true
val=`expr $b % $a`
echo "b % a : $val"

if [ $a == $b ]
then
   echo "a 等于 b"
fi
  • shell其他
-   将命令的结果赋值给变量
variable=`test.sh`
variable=$(test.sh)

eg: 
#! /bin/bash
variable=$(cat variable_first.sh)
echo $variable
variable_second=`cat variable_second.sh`
echo $variable_second



-   删除变量unset 
unset variable
eg:
myUnset='unset'
echo $myUnset


-  变量分类:全局变量,局部变量,环境变量
注:1.shell中变量都默认为全局变量,要想变成局部变量,使用local。
    2.进入子进程,执行bash。退出子进程,执行exit。
    3.进程类似于windows下一个应用窗口就是一个进程,进程是互不相干扰的。
    4.导出环境变量export,通过 export 导出的环境变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么环境变量也就随之消失了,其它的进程也就无法使用了,所以说环境变量也是临时的。
  • shell命令替换(重点)
命令:
variable=`command`或者variable=$(command)
注:多个命令之间用';'隔开
  • shell特殊参数和参数位置
eg:
#!/bin/bash
echo "Language: $1"
echo "URL: $2"

运行test.sh:
[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ . ./test.sh Shell http://c.baidu.net/shell/
Language: Shell
URL: http://c.biancheng.net/shell/


eg1:
#!/bin/bash
#定义函数
function func(){
    echo "Language: $1"
    echo "URL: $2"
}
#调用函数
func C++ http://c.biancheng.net/cplus/


运行test.sh:
[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ . ./test.sh
Language: C++
URL: http://c.biancheng.net/cplus/


特殊参数
变量            |           说明
----------------|--------------------------------------------------------------------
$0	        | 当前脚本的文件名
$n(n≥1)         | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1,第二个参数是 $2。 
$#              | 传递给脚本或函数的参数个数 
$*              | 传递给脚本或函数的所有参数。 
$@              | 传递给脚本或函数的所有参数。当被双引号" "包含时,$@ 与 $* 稍有不同  
$?              | 上个命令的退出状态,或函数的返回值   
$$              | 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID
注释:



  • 备注
-   $()与``针对数学计算的使用
    1.使用shell自带的函数时,$(expr $($1 + $2)) 或者 `expr $1 + $2`
    2.注意数学计算时,参数之间的间隔

-   shell脚本转义
    echo "print each param from \"\$*\"" 注:转义使用\"\$*"\
    
-   $*与$@都是打印传递给脚本或者函数的所有参数,但是在双引号中,两者有着本质区别,"$*""的循环次数要比"$@"少

-   shell脚本中字符串可以用“”或者''包裹使用,也可以不带引号的使用
    eg:
    #! /bin/bash
    
    a=test
    echo $a
    
    结果:
    [root@localhost shell_study]# bash string.sh 
    test
    


  • shell的内置命令和外部命令
-   bash shell内置命令汇总
命令                	说明
:               扩展参数列表,执行重定向操作
.               读取并执行指定文件中的命令(在当前 shell 环境中)
alias	        为指定命令定义一个别名
bg          	将作业以后台模式运行
bind	        将键盘序列绑定到一个 readline 函数或宏
break	        退出 for、while、select 或 until 循环
builtin	        执行指定的 shell 内建命令
caller      	返回活动子函数调用的上下文
cd              将当前目录切换为指定的目录
command	        执行指定的命令,无需进行通常的 shell 查找
compgen	        为指定单词生成可能的补全匹配
complete        显示指定的单词是如何补全的
compopt	        修改指定单词的补全选项
continue        继续执行 for、while、select 或 until 循环的下一次迭代
declare	        声明一个变量或变量类型。
dirs	        显示当前存储目录的列表
disown	        从进程作业表中刪除指定的作业
echo	        将指定字符串输出到 STDOUT
enable	        启用或禁用指定的内建shell命令
eval        	将指定的参数拼接成一个命令,然后执行该命令
exec        	用指定命令替换 shell 进程
exit	        强制 shell 以指定的退出状态码退出
export	        设置子 shell 进程可用的变量
fc              从历史记录中选择命令列表
fg              将作业以前台模式运行
getopts	        分析指定的位置参数
hash        	查找并记住指定命令的全路径名
help        	显示帮助文件
history     	显示命令历史记录
jobs        	列出活动作业
kill        	向指定的进程 ID(PID) 发送一个系统信号
let         	计算一个数学表达式中的每个参数
local       	在函数中创建一个作用域受限的变量
logout      	退出登录 shell
mapfile     	从 STDIN 读取数据行,并将其加入索引数组
popd        	从目录栈中删除记录
printf      	使用格式化字符串显示文本
pushd       	向目录栈添加一个目录
pwd         	显示当前工作目录的路径名
read        	从 STDIN 读取一行数据并将其赋给一个变量
readarray   	从 STDIN 读取数据行并将其放入索引数组
readonly    	从 STDIN 读取一行数据并将其赋给一个不可修改的变量
return      	强制函数以某个值退出,这个值可以被调用脚本提取
set             设置并显示环境变量的值和 shell 属性
shift       	将位置参数依次向下降一个位置
shopt       	打开/关闭控制 shell 可选行为的变量值
source      	读取并执行指定文件中的命令(在当前 shell 环境中)
suspend	        暂停 Shell 的执行,直到收到一个 SIGCONT 信号
test	        基于指定条件返回退出状态码 0 或 1
times       	显示累计的用户和系统时间
trap	        如果收到了指定的系统信号,执行指定的命令
type        	显示指定的单词如果作为命令将会如何被解释
typeset     	声明一个变量或变量类型。
ulimit	        为系统用户设置指定的资源的上限
umask       	为新建的文件和目录设置默认权限
unalias	        刪除指定的别名
unset       	刪除指定的环境变量或 shell 属性
wait        	等待指定的进程完成,并返回退出状态码


- 使用type命令检测是否shell内置命令
[root@localhost ~]# type cd
cd is a Shell builtin
[root@localhost ~]# type ifconfig
ifconfig is /sbin/ifconfig



- alias&& unalias 给命令创建(删除)别名,格式alias new_name='command'
eg:
    关机命令:
    alias myShutdown='shutdown -h now'
  
  
    
    
-  read 读取键盘输入
read命令格式:read [-options] [variables]

read相关参数
        选项	            说明
    -a array        把读取的数据赋值给数组 array,从下标 0 开始。
    -d delimiter    用字符串 delimiter 指定读取结束的位置,而不是一个换行符(读取到的数据不包括 delimiter)。
    -e              在获取用户输入的时候,对功能键进行编码转换,不会直接显式功能键对应的字符。
    -n num          读取 num 个字符,而不是整行字符。
    -p prompt       显示提示信息,提示内容为 prompt。
    -r              原样读取(Raw mode),不把反斜杠字符解释为转义字符。
    -s              静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的。
    -t seconds      设置超时时间,单位为秒。如果用户没有在指定时间内输入完成,那么 read 将会返回一个非 0 的退出状态,表示读取失败。
    -u fd           使用文件描述符 fd 作为输入源,而不是标准输入,类似于重定向。
eg:
#! /bin/bash

read -p "enter params:" name url total
echo "网站名: $name"
echo "网站地址: $url"
echo "网站访问量: $total"

结果:
[root@localhost shell_study]# bash read_info.sh 
enter params:自学网 51about.com 1000
网站名: 自学网
网站地址: 51about.com
网站访问量: 1000




-   exit退出当前进程,$?查看退出当前进程状态




-   declare 和 typeset(废弃):设置变量属性
declare命令格式:declare [+/-] [aAfFgilprtux] [变量名=变量值]
其中,-表示设置属性,+表示取消属性,aAfFgilprtux都是具体的选项,它们的含义如下表所示:
        选项            	    含义
    -f [name]           列出之前由用户在脚本中定义的函数名称和函数体。
    -F [name]           仅列出自定义函数名称。
    -g name             在 Shell 函数内部创建全局变量。
    -p [name]           显示指定变量的属性和值。
    -a name             声明变量为普通数组。
    -A name             声明变量为关联数组(支持索引下标为字符串)。
    -i name 	        将变量定义为整数型。
    -r name[=value]     将变量定义为只读(不可修改和删除),等价于 readonly name。
    -x name[=value]     将变量设置为环境变量,等价于 export name[=value]。


eg:
#! /bin/bash

declare -a arr array result
arr=(1 2 3 4 5)
array=('aa' 'bb' 'cc')

result=(${arr[*]} ${array[*]})
echo ${result[@]}

结果:
[root@localhost shell_study]# bash string_declare.sh 
1 2 3 4 5 aa bb cc




-   逻辑运算时,注意如下
[root@localhost shell_study]# a=100
[root@localhost shell_study]# echo $((a++))
100 //注意输出结果为100
[root@localhost shell_study]# echo $a
101 //注意输出结果为101
[root@localhost shell_study]# a=10
[root@localhost shell_study]# echo $((a--))
10 //输出结果为10
[root@localhost shell_study]# echo $a
9 //输出结果为9




-   多项逻辑运算,格式:((a=3+5, b=a+10)) 



-   test
    1.用法:test expression,当 test 判断 expression 成立时,退出状态为 0,否则为非 0 值。
    
    2.文件类型判断
    选 项	    作 用
-b filename	判断文件是否存在,并且是否为块设备文件。
-c filename	判断文件是否存在,并且是否为字符设备文件。
-d filename	判断文件是否存在,并且是否为目录文件。
-e filename	判断文件是否存在。
-f filename	判断文件是否存在,井且是否为普通文件。
-L filename	判断文件是否存在,并且是否为符号链接文件。
-p filename	判断文件是否存在,并且是否为管道文件。
-s filename	判断文件是否存在,并且是否为非空。
-S filename	判断该文件是否存在,并且是否为套接字文件。

    3.文件权限判断
     选 项   	    作 用
-r filename	判断文件是否存在,并且是否拥有读权限。
-w filename	判断文件是否存在,并且是否拥有写权限。
-x filename	判断文件是否存在,并且是否拥有执行权限。
-u filename	判断文件是否存在,并且是否拥有 SUID 权限。
-g filename	判断文件是否存在,并且是否拥有 SGID 权限。
-k filename	判断该文件是否存在,并且是否拥有 SBIT 权限

    4.文件比较
            选 项	                作 用
filename1 -nt filename2 	判断 filename1 的修改时间是否比 filename2 的新。
filename -ot filename2  	判断 filename1 的修改时间是否比 filename2 的旧。
filename1 -ef filename2 	判断 filename1 是否和 filename2 的 inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法


eg:
#! /bin/bash

read a
read b
if test $a>$b
then
	echo 1
else
	echo 0
fi 
结果:
[root@localhost shell_study]# bash test.sh
1
2
1
  • 选择结构
1.if elif结构
if  condition1
then
   statement1
elif condition2
then
    statement2
elif condition3
then
    statement3
……
else
   statementn
fi
2.if else结构
if  condition
then
   statement1
else
   statement2
fi


3.case结构
case expression in
    pattern1)
        statement1
        ;;
    pattern2)
        statement2
        ;;
    pattern3)
        statement3
        ;;
    ……
    *)
        statementn
esac

  • 循环结构
1.while循环
while condition
do
    statements
done

2.until循环(条件不成立时才进行循环,一旦判断条件成立,就终止循环)
until condition
do
    statements
done

3.for循环
for((exp1; exp2; exp3))
do
    statements
done

4.for in循环
for variable in value_list
do
    statements
done

5.select in循环
select variable in value_list
do
    statements
done
  • 函数定义与调用
格式一:
function name() {
    statements
    [return value]
}

格式二:
name() {
    statements
    [return value]
}

格式三:
function name {
    statements
    [return value]
}

eg:
#! /bin/bash

function getsum(){
	local sum=0
	for n in $@
	do
		((sum+=n))
	done
	return $sum
}

getsum 10 20 30 40 50 #调用函数并传递参数
echo $?

运行结果:150


eg:
#!/bin/bash
function getsum(){
    local sum=0
    for n in $@
    do
         ((sum+=n))
    done
    echo $sum
    return 0
}
#调用函数并传递参数,最后将结果赋值给一个变量
total=$(getsum 10 20 55 15)
echo $total
#也可以将变量省略
echo $(getsum 10 20 55 15)

----------------shell未完待续--------------------

你可能感兴趣的:(linux)