流程控制

Shell 编写的程序是顺序执行的,也就是说第一命令先执行,然后接着执行第二条命令,然后再下一条,以此类推,而流程控制就是改变上面这种顺序执行的方式。

流程控制语句用于控制程序的流程,以实现程序的各种结构方式,即用来实现对程序流程的选择、循环、转向和返回等进行控制。

流程语句中需要依赖到条件表达式,也就是 [[Shell 中的 test 测试命令|test 测试命令]]。

Shell 中的流程控制语句和其他编程语言的流程语句大体相同,分为:

  • if 条件判断语句
  • case 条件判断语句
  • for 循环语句
  • while 循环语句
  • until 循环语句
  • 特殊流程控制语句

条件判断语句

if 条件语句分为单分支语句和多分支语句。

单分支if条件语句

单分支条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事情也不做。

语法如下:

1
2
3
if[ 条件判断表达式 ];then
程序
fi

if语句使用fi结尾,和其他编程语言使用大括号结尾不同。

[ 条件表达式 ] 就是使用 [[Shell 中的 test 测试命令|test]] 命令进行判断,在test命令中,使用 [] 来简写test命令的花,中括号和条件表达式之间必须有空格。

then 后面跟着符合条件之后执行的程序,可以放在 [] 之后,用 ; 分割;也可以换行写入,这样就不需要 ; 了。示例:

1
2
3
4
if [ 条件表达式 ]
then
程序
fi

示例,如果根分区的使用率大于等于 80% 时则报警。

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
38
39
40
41
42
# 1.获取根分区使用率
# 1.1 通过df命令查看Linux系统上的文件系统磁盘使用情况。
# df命令用于显示目前在Linux系统上文件系统磁盘使用情况的统计。
[root@cjh tmp]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 19G 2.1G 16G 12% /
tmpfs 491M 0 491M 0% /dev/shm
/dev/sda1 240M 34M 194M 15% /boot
# 1.2 把根分区的磁盘使用情况提取出来
[root@cjh tmp]# df -h | grep /dev/sda3
/dev/sda3 19G 2.1G 16G 12% /
# 1.3 然后用awk命令,进行列信息提取,提取第五列。
[root@cjh tmp]# df -h | grep /dev/sda3 | awk '{print $5}'
12%
# 1.4 截取前面的数字部分,方便后边判断使用。
# 以%作为分隔符,然后提取1列。
[root@cjh tmp]# df -h | grep /dev/sda3 | awk '{print $5}' | cut -d "%" -f 1
12
# 2.编写Shell程序
# 2.1 创建一个Shell文件if1.sh
[root@cjh tmp]# vim if1.sh
# 编写内容如下:
#!/bin/bash
# 把根分区使用率作为变量值赋予变量rate
# 把上面的命令以命令行的方式先敲一遍,确认能获取到我们需要的内容。
# 如果在Shell里面直接写,会有很大难度。
rate=$( df -h | grep /dev/sda3 | awk '{print $5}' | cut -d "%" -f 1 )
# 判断rate的值如果大于等于80,则执行then后的程序。
# 我们这里为了有演示效果,把输出调整为10.
if [ $rate -ge 10 ]
then
# 打印警告信息。在实际工作中,也可以向管理员发送邮件。
echo "Warning! /dev/sda3 is full !!!"

fi

# 上面的程序表示,如果根分区使用率超过80%则打印`Warning! /dev/sda3 is full !!!``,没有则什么都不做。

# 3. 给if1.sh文件赋予执行权限,并执行该脚本。
[root@cjh tmp]# chmod 755 if1.sh
[root@cjh tmp]# ./if1.sh
Warning! /dev/sda3 is full !!!

双分支if条件语句

语法格式:

1
2
3
4
5
6
if [ 条件表达式 ]
then
条件成立时
else
条件不成立时
fi

多分支if条件语句

语法格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if [ 条件表达式1 ]
then
条件表达式1成立时
elif [ 条件表达式2 ]
then
条件表达式2成立时
elif [ 条件表达式3 ]
then
条件表达式3成立时
...更多条件

else
当所有条件都不成立时
fi

示例:

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
# 编写程序,判断用键盘输入的值与5进行判断
[root@cjh tmp]# vim if.sh


#!/bin/bash

read -t 30 -p "please input number:" number

if [ $((number)) -eq 5 ]
then
echo "input number equls 5"
elif [ "$number" -lt 5 ]
then
echo "input number lt 5"
else
echo "input number ge 5"
fi

[root@cjh tmp]# chmod +x if.sh
# 执行脚本
[root@cjh tmp]# ./if.sh
please input number:1
input number lt 5

[root@cjh tmp]# ./if.sh
please input number:5
input number equls 5

[root@cjh tmp]# ./if.sh
please input number:9
input number ge 5

多分支case语句

case 语句和 if-else 语句都是多分支条件语句,不过和if-else语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。

语法格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;

…省略其他分支…

*)
如果变量的值都不是以上的值,则执行此程序
;;
esac (注:case的反写)

那case语句和if-else语句有什么区别?

  • case语句只能判断一个条件,是否符合某一种情况,是一种判断
  • 而if-else语句有多个分支语句,可以判断一个输入是否唯恐,是否是文件,是否是目录等多种条件关系,是不同的判断。

在 case 语句中,会取出变量中的值,然后与语句体中的值逐一比较;如果数值符合,则执行对应的程序,如果数值不符合,则依次比较下一个值;

如果所有的值都不符合,则会执行 *) 下的程序,*) 代表所有其他值;

case 语句 以 case 开头,以 esac 结尾,是 case 的反写;

每一个分支程序之后都要通过 ;; 双分号结尾,代表该程序段结束。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# 请输入你需去往的城市
echo "want to beijing,please input 1."
echo "want to shanghai,please input 2."
echo "want to chendu,please input 3."
# 接收输入的信息,赋值给变量cho
read -t 30 -p "please input your choice: " cho
# case条件判断
case $cho in
"1")
echo "to beijin"
;;
"2")
echo "to shanghai"
;;
"3")
echo "to chendu"
;;
*)
echo "error input"
;;
esac

循环语句

在Shell中,循环语句有for、while和until

for

for循环是固定循环,也就是在循环时就已经知道需要进行几次的循环,有时候也会把for循环称为计数循环。

for循环的语法格式有2种:

1
2
3
4
5
6
7
8
9
10
11
# 语法1:
for 变量 in 值1 值2 值3 …
do
程序
done

# 语法2:
for((初始值;循环控制条件;变量变化))
do
程序
done

语法1中的for循环次数,取决于in后面值的个数(空格分隔),有几个值就循环几次,并且每次循环都把该值赋予给变量。也就是说,假设in后面有三个值,for循环会循环三次,第一次循环把值1赋值给变量,第二次循环会把值2赋值给变量,第三次循环会把值3赋值给变量,以此类推。

语法2与其他编程语言的for循环一致。

语法1示例:

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

[root@cjh tmp]# vim for.sh
#!/bin/bash
for i in 1 2 3 4 5 6 7
do
if [ "$i" -eq 7 ]
then
echo "今天是周日"
elif [ "$i" -eq 6 ]
then
echo "今天是周六"
else
echo "今天是周"$i
fi
done

[root@cjh tmp]# chmod +x for3.sh
[root@cjh tmp]# ./for.sh
今天是周1
今天是周2
今天是周3
今天是周4
今天是周5
今天是周六
今天是周日

有时候不能像示例中能到所有值,一般都是个变量,那变量该如何用到for循环里面呢?答案是可以的,示例:

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

[root@cjh tmp]# vim for2.sh
#!/bin/bash

ls >> count.log
count=0

for i in $(cat count.log)
do
count=$(($count+1))
echo "文件名:$i,count:$count"
done

[root@cjh tmp]# chmod +x for3.sh
[root@cjh tmp]# ./for2.sh
文件名:count.log,count:1
文件名:Desktop,count:2
文件名:Documents,count:3
文件名:Downloads,count:4
文件名:for2.sh,count:5
文件名:for.sh,count:6
文件名:go,count:7
文件名:Library,count:8
文件名:Music,count:9
文件名:note,count:10
文件名:Pictures,count:11
文件名:project,count:12
文件名:software,count:13
文件名:Videos,count:14

语法2示例:

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
[root@cjh tmp]# vim for3.sh

#!/bin/bash

# 首先先拿到要执行循环的次数
count=$(ls | wc -l)

for((i=1;i<="$count";i=i+1))
do
echo "i:$i"
done

[root@cjh tmp]# chmod +x for3.sh
[root@cjh tmp]# ./for3.sh
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
i:10
i:11
i:12
i:13
i:14

while

对while循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。和for循环的第二种格式for(初始值;循环控制条件;变量变化)类似。

语法格式:

1
2
3
4
while [ 条件判断式 ]
do
程序
done

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# 给变量i和变量s赋值
# 从1开始相加
i=1
# 求和变量
sum=0
# 执行while循环求和
# 如果变量i的值小于等于100,则执行循环
while [ $i -le 100 ]
do
sum=$(( $sum+$i ))
i=$(( $i+1 ))
done
# 输出求和结果
echo "The sum is:$sum"

until

unti1循环和whi1e循环相反,unti1循环时只要条件判断式不成立侧进行循环,并执行循环程序。一旦循环条件成立,则终止循环。

语法格式:

1
2
3
4
until [ 条件判断式 ]
do
程序
done

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# 给变量i和变量s赋值
# 从1开始相加
i=1
# 求和变量
sum=0
# 执行while循环求和
# 如果变量i的值大于100,则执行循环
until [ $i -gt 100 ]
do
sum=$(( $sum+$i ))
i=$(( $i+1 ))
done
# 输出求和结果
echo "The sum is:$sum"

特殊流程控制语句

除了if…else、case、for、while、until这5种流程控制语句外,还有一些特殊的流程控制语句。

比如:exit语句、break语句、continue语句。

exit

系统有一个exit语句,用于退出当前用户的登录状态;或者是退出当前终端。

可是在Shell脚本中,exit语句是用来退出当前脚本的。也就是说,在Shell脚本当中,只要碰到了exit语句,后续的程序就不会再执行,而是直接退出脚本。

语法格式:

1
exit [返回值]

后面的breank语句和continue语句与其他编程语言的相同,不再赘述。