流程控制是改变程序运行顺序的指令。
4.1 if语句
4.1.1 单分支
1
2
3
|
if 条件表达式; then 命令 fi |
示例:
1
2
3
4
5
6
7
|
#!/bin/bash N=10 if [ $N -gt 5 ]; then echo yes fi # bash test.sh yes |
4.1.2 双分支
1
2
3
4
5
|
if 条件表达式; then 命令 else 命令 fi |
示例1:
1
2
3
4
5
6
7
8
9
|
#!/bin/bash N=10 if [ $N -lt 5 ]; then echo yes else echo no fi # bash test.sh no |
示例2:判断crond进程是否运行
1
2
3
4
5
6
7
8
|
#!/bin/bash NAME=crond NUM=$( ps -ef | grep $NAME | grep -vc grep ) if [ $NUM - eq 1 ]; then echo "$NAME running." else echo "$NAME is not running!" fi |
示例3:检查主机是否存活
1
2
3
4
5
6
|
#!/bin/bash if ping -c 1 192.168.1.1 > /dev/null ; then echo "OK." else echo "NO!" fi |
if语句可以直接对命令状态进行判断,就省去了获取$?这一步!
4.1.3 多分支
1
2
3
4
5
6
7
|
if 条件表达式; then 命令 elif 条件表达式; then 命令 else 命令 fi |
当不确定条件符合哪一个时,就可以把已知条件判断写出来,做相应的处理。
示例1:
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash N=$1 if [ $N - eq 3 ]; then echo "eq 3" elif [ $N - eq 5 ]; then echo "eq 5" elif [ $N - eq 8 ]; then echo "eq 8" else echo "no" fi |
如果第一个条件符合就不再向下匹配。
示例2:根据Linux不同发行版使用不同的命令安装软件
1
2
3
4
5
6
7
8
9
|
#!/bin/bash if [ -e /etc/redhat-release ]; then yum install wget -y elif [ $( cat /etc/issue | cut -d ' ' -f1`) == "Ubuntu" ]; then apt-get install wget -y else Operating system does not support. exit fi |
4.2 for语句
1
2
3
|
for 变量名 in 取值列表; do 命令 done |
示例:
1
2
3
4
5
6
7
8
|
#!/bin/bash for i in {1..3}; do echo $i done # bash test.sh 1 2 3 |
for的语法也可以这么写:
1
2
3
4
5
6
7
8
|
#!/bin/bash for i in $@; { echo $i } # bash test.sh 1 2 3 1 2 3 |
默认for循环的取值列表是以空白符分隔,也就是第一章讲系统变量里的$IFS:
1
2
3
4
5
6
7
|
#!/bin/bash for i in 12 34; do echo $i done # bash test.sh 12 34 |
如果想指定分隔符,可以重新赋值$FS变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#!/bin/bash OLD_IFS=$IFS IFS= ":" for i in $( head -1 /etc/passwd ); do echo $i done IFS=$OLD_IFS # 恢复默认值 # bash test.sh root x 0 0 root /root /bin/bash |
for循环还有一种C语言风格的语法:
1
2
3
4
|
#!/bin/bash for ((i=1;i<=5;i++)); do echo $i done |
示例1:检查多个主机是否存活
1
2
3
4
5
6
7
8
|
#!/bin/bash for ip in 192.168.1.{1..254}; do if ping -c 1 $ip > /dev/null ; then echo "$ip OK." else echo "$ip NO!" fi done |
示例2:检查多个域名是否可以访问
1
2
3
4
5
6
7
8
9
10
|
#!/bin/bash URL= "www.baidu.com www.sina.comwww.jd.com" for url in $URL; do HTTP_CODE=$(curl -o /dev/null -s -w %{http_code} http: // $url) if [ $HTTP_CODE - eq 200 -o $HTTP_CODE - eq 301 ]; then echo "$url OK." else echo "$url NO!" fi done |
博客地址:http://lizhenliang.blog.51cto.com
QQ群:323779636(Shell/Python运维开发群)
4.3 while语句
1
2
3
|
while 条件表达式; do 命令 done |
示例1:
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/bin/bash N=0 while [ $N -lt 5 ]; do let N++ echo $N done # bash test.sh 1 2 3 4 5 |
当条件表达式为true时,终止循环。
示例2:条件表达式为true,将会产生死循环
1
2
3
4
|
#!/bin/bash while [ 1 - eq 1 ]; do echo "yes" done |
也可以条件表达式直接用true:
1
2
3
4
|
#!/bin/bash while true ; do echo "yes" done |
还可以条件表达式用冒号,冒号在Shell中的意思是不做任何操作。但状态是0,因此为true:
1
2
3
4
|
#!/bin/bash while :; do echo "yes" done |
示例3:在死循环中,满足条件终止循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/bin/bash N=0 while true ; do let N++ if [ $N - eq 5 ]; then break fi echo $N done # bash test.sh 1 2 3 4 |
里面用了if判断,并用了break语句,它是跳出循环。与其关联的还有一个continue语句,它是跳出本次循环。
示例4:举例子说明continue用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/bin/bash N=0 while [ $N -lt 5 ]; do let N++ if [ $N - eq 3 ]; then continue fi echo $N done # bash test.sh 1 2 4 5 |
当变量N等于3时,continue跳过了当前循环,没有执行下面的echo。
注意:continue与break语句只能循环语句中使用。
示例5:逐行处理文本
文本内容:
1
2
3
4
|
# cat a.txt a b c 1 2 3 x y z |
要想使用while循环逐行读取a.txt文件,有三种方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
方式1: #!/bin/bash cat . /a .txt | while read LINE; do echo $LINE done 方式2: #!/bin/bash while read LINE; do echo $LINE done < . /a .txt 方式3: #!/bin/bash exec < . /a .txt # 读取文件作为标准输出 while read LINE; do echo $LINE done |
与while关联的还有一个until语句,它与while不同之处在于,是当条件表达式为false时才循环,实际使用中比较少,这里不再讲解。
4.4 case语句
case语句一般用于选择性来执行对应部分块命令。
1
2
3
4
5
6
7
8
9
10
|
case 模式名 in 模式1) 命令 ;; 模式2) 命令 ;; *) 不符合以上模式执行的命令 esac |
每个模式必须以右括号结束,命令结尾以双分号结束。
示例:根据位置参数匹配不同的模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/bin/bash case $1 in start) echo "start." ;; stop) echo "stop." ;; restart) echo "restart." ;; *) echo "Usage: $0 {start|stop|restart}" esac # bash test.sh Usage: test .sh {start|stop|restart} # bash test.sh start start. # bash test.sh stop stop. # bash test.sh restart restart. |
上面例子是不是有点眼熟,在Linux下有一部分服务启动脚本都是这么写的。
模式也支持正则,匹配哪个模式就执行那个:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/bin/bash case $1 in [0-9]) echo "match number." ;; [a-z]) echo "match letter." ;; '-h' | '--help' ) echo "help" *) echo "Input error!" exit esac # bash test.sh 1 match number. # bash test.sh a match letter. # bash test.sh -h help # bash test.sh --help help |
模式支持的正则有:*、?、[ ]、[.-.]、|。后面有章节单独讲解Shell正则表达式。
4.5 select语句
select是一个类似于for循环的语句。
1
2
3
|
select 变量 in 选项1 选项2; do break done |
示例:
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash select mysql_version in 5.1 5.6; do echo $mysql_version done # bash test.sh 1) 5.1 2) 5.6 #? 1 5.1 #? 2 5.6 |
用户输入编号会直接赋值给变量mysql_version。作为菜单用的话,循环第二次后就不再显示菜单了,并不能满足需求。
在外面加个死循环,每次执行一次select就break一次,这样就能每次显示菜单了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/bin/bash while true ; do select mysql_version in 5.1 5.6; do echo $mysql_version break done done # bash test.sh 1) 5.1 2) 5.6 #? 1 5.1 1) 5.1 2) 5.6 #? 2 5.6 1) 5.1 2) 5.6 |
如果再判断对用户输入的编号执行相应的命令,如果用if语句多分支的话要复杂许多,用case语句就简单多了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#!/bin/bash PS3= "Select a number: " while true ; do select mysql_version in 5.1 5.6 quit; do case $mysql_version in 5.1) echo "mysql 5.1" break ;; 5.6) echo "mysql 5.6" break ;; quit) exit ;; *) echo "Input error, Please enter again!" break esac done done # bash test.sh 1) 5.1 2) 5.6 3) quit Select a number: 1 mysql 5.1 1) 5.1 2) 5.6 3) quit Select a number: 2 mysql 5.6 1) 5.1 2) 5.6 3) quit Select a number: 3 |
如果不想用默认的提示符,可以通过重新赋值变量PS3来自定义。这下就比较完美了!