流程控制是改变程序运行顺序的指令。
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来自定义。这下就比较完美了!