一、认识shell
什么是shell?shell为单词外壳的意思。那么这是谁的外壳?我们知道一个系统中实际工作的是那些硬件,cpu、内存、磁盘等。我们如何调用这些硬件为我们工作?实际上,硬件是由内核kernel控制的。我们可以通过kernel控制硬件,但我们不能直接和内核kernel交流。我们需要一个外壳,这个外壳就是shell来沟通kernel。何为shell脚本,其实不过是一堆命令写在一个文件中,这个文件具有执行权限。
二、变量
什么是变量?变量是脚本编程中数据表现的一中方法,变量是系统为了保留数据项在内存空间中分配一个位置或者一组位置的标识或名字。bash变量是不区分类型的,本质上都是字符串。
2.1 特殊的变量类型
本地变量:只对当前的shell进程有效,对其它shell进程无效,包含当前shell进程的子进程
[leon@localhost ~]$ test=string #定义一个本地变量 [leon@localhost ~]$ echo $test string [leon@localhost ~]$ bash #打开一个子shell [leon@localhost ~]$ echo $test [leon@localhost ~]$ #为null值
环境变量:对当前shell进程和子进程有效,对其它shell无效
[leon@localhost ~]$ export test=string #定义一个环境变量 [leon@localhost ~]$ echo $test string [leon@localhost ~]$ bash [leon@localhost ~]$ echo $test string
局部变量:对shell脚本中某段代码片段有效,通常用于函数本地,通常用local来定义
[leon@localhost tmp]$ cat test.sh #!/bin/bash #定义使用哪种shell解析脚本 # function test { #定义一个函数 local a=local #定义一个局部变量 echo $a } test && echo $a [leon@localhost tmp]$ ./test.sh local
位置变量:$0 $1 $2…$n
[leon@localhost tmp]$ sh test1.sh 1 [leon@localhost tmp]$ cat test1.sh #!/bin/bash # echo $0 echo $1 echo $2 [leon@localhost tmp]$ sh test1.sh string1 string2 string3 #传递位置参数 test1.sh string1 string2
常用的特殊变量:$? $@ $* $# $$
[leon@localhost tmp]$ cat test2.sh #!/bin/bash # echo $* echo $@ echo $# echo $? echo $$ [leon@localhost tmp]$ sh test2.sh string1 string2 string3 string4 string1 string2 string3 string4 string1 string2 string3 string4 4 0 1650
数组 :是特殊的变量,bash支持一维数组。数组由数组名+索引 组成。
如:a[1] a[2] a[3] … a[N] a[hello] a[Number] a[string] …
2.2 变量的声明及赋值
1.不能使用系统内置变量
2.以字母,数字,下划线组成,不能以数字开头
3.见名知义
[leon@localhost tmp]$ PATH=/tmp [leon@localhost tmp]$ ls bash: ls: command not found [leon@localhost ~]$ [leon@localhost ~]$ 1test=test -bash: 1test=test: command not found
定义整型的变量
[leon@localhost ~]$ declare -i number=23 #使用declare -i定义一个整型变量
定义数组
可以使用declare 定义
[leon@localhost ~]$ declare -a a=(1 2 3 4) #定义一个数组 [leon@localhost ~]$ echo ${a[@]} 1 2 3 4 [leon@localhost ~]$ b=(1 2 3 4) [leon@localhost ~]$ echo ${b[@]} 1 2 3 4 [leon@localhost ~]$ declare -A string=([hello]='hello' [day]='sunday') #定义一个关联型数组 [leon@localhost ~]$ echo ${string[@]} sunday hello [leon@localhost ~]$ logs=(/home/*) #给变量赋值 [leon@localhost ~]$ echo ${logs[@]} /home/leon /home/openstack /home/test
三、数组及字符串操作
3.1 数组操作
3.1.1 数组长度
${#ARRAY[*]}
${#ARRAY[@]}
[leon@localhost ~]$ declare -A string=([hello]='hello' [day]='sunday') [leon@localhost ~]$ echo ${#string[@]} && echo ${#string[*]} 2 2
3.1.2 数组中挑选某些元素
${ARRAY[@]:offset:number}
[leon@localhost ~]$ echo ${string[@]} sunday hello [leon@localhost ~]$ echo ${string[@]:1:1} sunday [leon@localhost ~]$ echo ${string[@]:1:2} sunday hello [leon@localhost ~]$ echo ${string[@]:1} sunday hello
3.1.3 数组的删除
unset ARRAY
[leon@localhost ~]$ echo ${logs[@]} /home/leon /home/openstack /home/test [leon@localhost ~]$ unset logs[1] #删除索引为1的数组 [leon@localhost ~]$ echo ${logs[@]} /home/leon /home/test [leon@localhost ~]$ unset logs [leon@localhost ~]$ echo ${logs[@]} [leon@localhost ~]$
3.2 字符串操作
3.2.1 字符串取子串
${string:offset:length} :从第offset个向右取length个字符串
[leon@localhost ~]$ string=a1b2c3d4e5f6 [leon@localhost ~]$ echo ${string} a1b2c3d4e5f6 [leon@localhost ~]$ echo ${string:1:4} 1b2c
${string: -length} :从右向左取length个字符串
[leon@localhost ~]$ echo ${string} a1b2c3d4e5f6 [leon@localhost ~]$ echo ${string: -2} f6
${string#*word} :在string中存储字符串上,自左而右,查找第一次出现word,删除字符开始到此word处的所有内容
[leon@localhost ~]$ string=string-hello-myname-is-hello-over [leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string#*hello} -myname-is-hello-over
${string##*word} :在string中存储字符串上,自左而右,查找最后一次出现word,删除字符开始到此word处的所有内容
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string#*hello} -myname-is-hello-over [leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string##*hello} -over
${string%word*}在string中存储的字符串上,自右而左,查找第一次出现的word,删除字符开始到此word处的所有内容
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string%hello*} string-hello-myname-is-
${string%%word*}在string中存储的字符串上,自右而左,查找最后一次出现的word,删除字符开始到此word处的所有内容
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string%%hello*} string-
3.2.2 字符串查找替换
${string/pattern/substi} :替换第一次出现的字符串
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string/hello/hi} string-hi-myname-is-hello-over
${sting//pattern/substi} :替换所有出现过的字符串
[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string//hello/hi} string-hi-myname-is-hi-over ${string/pattern} [leon@localhost ~]$ echo ${string//hello/hi} [leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string/hello} string--myname-is-hello-over ${string//pattern}[leon@localhost ~]$ echo $string string-hello-myname-is-hello-over [leon@localhost ~]$ echo ${string//hello} string--myname-is--over [leon@localhost ~]$
四、流程控制
4.1 选择分支
4.1.1 条件测试
条件测试中,如果为真,则返回执行状态为0的值,否则返回执行状态为非0的值
整型测试:数值之间比较大小 字符型比较
-gt -lt -eq -ge -le > < == != >= <= -n -z
常用文件测试
-e 文件存在
[leon@localhost ~]$ [ -e /tmp/xxxxxxx ] [leon@localhost ~]$ echo $? 1
-d 文件存在且为目录
[leon@localhost ~]$ [ -d /tmp ] [leon@localhost ~]$ echo $? 0
-f 文件存在且为普通文件
[leon@localhost ~]$ [ -f /tmp ] [leon@localhost ~]$ echo $? 1
-r 文件是否具有可读权限
[leon@localhost ~]$ [ -r /root ]
[leon@localhost ~]$ echo $?
1
-w 文件是否具有可写权限
[leon@localhost ~]$ [ -w /home/leon ] [leon@localhost ~]$ echo $? 0
-x 文件是否具有可执行权限
[leon@localhost ~]$ [ -x /home/leon ] [leon@localhost ~]$ echo $? 0
组合条件测试 :在多个条件间实现逻辑运算
与: [ 条件一 -a 条件二 ]
条件一 && 条件二
[leon@localhost ~]$ [ -x /home -a -r /root ] [leon@localhost ~]$ echo $? 1 [leon@localhost ~]$ test -x /home && test -r /root [leon@localhost ~]$ echo $? 1
或: [ 条件一 -o 条件二 ]
条件一 || 条件二
[leon@localhost ~]$ [ -x /home -o -r /root ] [leon@localhost ~]$ echo $? 0 [leon@localhost ~]$ test -x /home || test -r /tmp [leon@localhost ~]$ echo $? 0
非:[ !条件 ]
[leon@localhost ~]$ [ ! -r /home/leon ] [leon@localhost ~]$ echo $? 1
4.1.2 if选择分支
语法: if 测试条件1;then
选择分支1
elif 测试条件2;then
选择分支2
……
elif 测试条件n;then
选择分支n
else
分支
fi
[leon@localhost ~]$ if true ; then echo true ;else echo false ;fi true[leon@localhost ~]$ [leon@localhost ~]$ if id test1 &>/dev/null ; then echo test1 ;elif id test2 &>/dev/null;then echo test2 ;elif id leon &>/dev/null ;then echo leon ;fi leon [leon@localhost ~]$ if [ $? -eq 0 ] ;then echo ture ;else echo false;fi ture
4.1.3 case选择分支
语法:case word in
pattern1)
分支1
;;
pattern2)
分支2
;;
patternN)
分支N
;;
*)
分支
;;
esac
[leon@localhost ~]$ case leon in root) id root ;; leon) echo leon ;; *) echo not this user! ;; esac leon [leon@localhost tmp]$ cat testCase.sh #!/bin/bsh # case $1 in 1) echo 1 ;; 2) echo 2 ;; 3) echo 3 ;; *) echo order ;; esac [leon@localhost tmp]$ chmod +x testCase.sh [leon@localhost tmp]$ sh testCase.sh order [leon@localhost tmp]$ ./testCase.sh 1 1
4.2 循环
4.2.1 for循环
语法1: for i in list ;do
list
done
语法2: for ((表达式一;条件表达式;表达式二));do
list
done
[leon@localhost tmp]$ for i in {1..5};do echo $i ;done 1 2 3 4 5 [leon@localhost tmp]$ for ((i=1;i<=5;i++));do echo $i ;done 1 2 3 4 5
4.2.2 while循环
语法1: while 测试条件; do
循环体
done
语法2: while read 变量名;do
循环体
done < /path/to/somefile
[leon@localhost tmp]$ cat testWhile.sh #!/bin/bash # declare -i i=1 while [ $i -le 5 ];do #比较i和5的大小,为真则进入循环,为假则退出循环 echo $i let i++ done [leon@localhost tmp]$ sh testWhile.sh 1 2 3 4 5 [leon@localhost tmp]$ cat testWhile.sh #!/bin/bash # while read userInfo;do echo $userInfo done < /etc/passwd [leon@localhost tmp]$ sh testWhile.sh root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin ...... openstack:x:502:502::/home/openstack:/bin/bash [leon@localhost tmp]$
4.2.3 until循环
语法:until 测试条件; do
循环体
done
[leon@vm tmp]$ cat testUntil.sh #!/bin/bash # declare -i i=5 until [ $i -lt 1 ];do #比较i和1的大小,为假就进入循环,为真则退出循环 echo $i let i-- done [leon@vm tmp]$ sh testUntil.sh 5 4 3 2 1
五、函数及返回值
语法1: function function_name {list}
语法2: function_name () {list}
[leon@vm tmp]$ cat testFunction.sh #!/bin/bash # function display { #定义一个名为display的函数 cat << NODE ------------------- ------meau--------- 1: install os 2: quit ------------------- NODE return 0 #退出函数并返回状态值0 echo next function_list } view() { display #调用函数 exit 1 #退出shell并返回状态值1 } view [leon@vm tmp]$ sh testFunction.sh ------------------- ------meau--------- 1: install os 2: quit ------------------- [leon@vm tmp]$ echo $? 1
六、循环控制
continue : 提前进入下一轮循环
[leon@vm tmp]$ cat testContinue.sh #/bin/bash # for (( i=1;i<=2;i++ )) ;do echo outside $i for (( n=1;n<=2;n++ ));do echo inside $n continue #直接进入下一循环 # break echo hello #这个echo语句用于没有将会执行 done done [leon@vm tmp]$ sh testContinue.sh outside 1 inside 1 inside 2 outside 2 inside 1 inside 2
break :跳出当前循环
[leon@vm tmp]$ cat testContinue.sh #/bin/bash # for (( i=1;i<=2;i++ )) ;do echo outside $i for (( n=1;n<=2;n++ ));do echo inside $n # continue break #退出当前循环 echo hello done done [leon@vm tmp]$ sh testContinue.sh outside 1 inside 1 outside 2 inside 1
七、信号捕捉
信号捕捉:trap 'COMMAND;COMMAND' SINGNAL
[leon@vm tmp]$ cat testTrap.sh #!/bin/bash # trap 'echo exit' SIGINT ping -c 100 www.baidu.com [leon@vm tmp]$ sh testTrap.sh #按ctrl+c时,捕捉到信号。 PING www.a.shifen.com (180.97.33.108) 56(84) bytes of data. 64 bytes from 180.97.33.108: icmp_seq=1 ttl=128 time=29.4 ms 64 bytes from 180.97.33.108: icmp_seq=2 ttl=128 time=29.5 ms ^C --- www.a.shifen.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1278ms rtt min/avg/max/mdev = 29.489/29.530/29.571/0.041 ms exit #退出脚本时执行echo语句输出
八、总结
shell编程是linux运维人员必须掌握的技能,shell不像其它C、C#、Java等高级编程语言那样有类和对象,面向对象等概念,但是shell可以有强大的命令支撑。毕竟我们是通过shell来沟通内核,不需要运行在虚拟机上。
原创文章,作者:成吉思汗,如若转载,请注明出处:http://www.178linux.com/8026
评论列表(1条)
总结的非常不错,文档功底很深