SHELL-流程控制
SHELL脚本-流程控制
1 if-then语句-判断
1.1 基本结构
if command;then
commands
fi
该结构的if语句可以用于判断if后的command是否执行成功,当该command执行成功(状态返回码为0),则执行then后的语句,否则退出。
if command;then
commands
else
commands
fi
该结构的if语句与上一结构功能类似,只是当command执行不成功的时候,执行else后的语句。
1.2 嵌套if
if command;then
commands
elif command;then
commands
else
commands
fi
这种嵌套的if语句,使用elif用于测试另外的命令,如果if后的command退出状态码为非0,则会测试elif后的命令,如果elif后的命令退出状态码为0则会执行,elif后的then语句,否则执行else语句。所以紧跟在elif语句的else语句,是属于elif的代码块,而不是if-then的代码块。
通过将多个elif语句联合起来,可以形成一个大规模的if-then-elif的嵌套组,从而实现类似于case语句的功能。
if command;then
commands
elif command;then
commands
elif command;then
commands
elif command;then
commands
fi
1.3 if的条件判断
与其他高级语言相同,if语句不仅可以根据命令的执行状态进行选择判断,也可以通过判断条件是否成立执行命令。
尽管if语句中的条件判断可以通过test命令实现,但最常使用的条件判断方法是使用方括号。
if [ condition ];then
commands
else
commands
fi
通过方括号执行条件判断需要注意的是,在条件判断语句和方括号左右两边均有空格隔开。
1.3.1 数值比较
假定变量 a 为 5,变量 b 为 10:
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
1.3.2 字符串比较
下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n "$a" ] 返回 true。 |
$ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
1.3.3 文件比较
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
其他检查符:
- -S: 判断某文件是否 socket。
- -L: 检测文件是否存在并且是一个符号链接。
1.4 if-then的高级特性
- 通过使用双方括号不仅可以使用标准的字符串比较,也可以通过正则表达式匹配字符。
- 通过使用双括号可以使用任意的书序赋值或比较表达式,双括号用到的其他运算符如下表
符号 | 描述 |
---|---|
val++ | 后增 |
val-- | 后减 |
++val | 先增 |
--val | 先减 |
! | 逻辑求反 |
~ | 位求反 |
** | 幂运算 |
<< | 左位移 |
>> | 右位移 |
& | 位布尔和 |
| | 位布尔或 |
&& | 逻辑和 |
|| | 逻辑或 |
1.5 case 语句
case var in
pattern1)
commands1
;;
pattern2)
commands2
;;
*)
commands3
;;
esac
case语句用于匹配同一变量的不同值,避免了使用if-then-elif的循环嵌套导致的逻辑混乱。语法结构更加清晰。
2 for while 循环语句
2.1 for语句基本格式
for var in list;do
commands
done
在list参数中,你需要提供迭代中要用到的一系列值。可以通过几种不同的方法指定列表 中的值。
在每次迭代中,变量var会包含列表中的当前值。第一次迭代会使用列表中的第一个值,第 二次迭代使用第二个值,以此类推,直到列表中的所有值都过一遍。
在do和done语句之间输入的命令可以是一条或多条标准的bash shell命令。在这些命令中, $var变量包含着这次迭代对应的当前列表项中的值。
list的值可以是数字,也可以是字符串。列表的值可以是由自己定义而来的,也可以是命令执行后的结果。常见的几种迭代定义方法:
#var值由192.168.1.2-192.168.1.150中循环迭代
for var in 192.168.1.{2..150}
#var值迭代文件夹/etc/下的所有文件或目录(通配符方法)
for var in /etc/*
#var值迭代文件夹/etc/下的所有文件或目录
for var in $(ls /etc)
#var值迭代1-6
for var in {1..6}
2.2 更改字段分隔符
for迭代字符串的中各个字符串的方法是由一个特殊的环境变量IFS定义的,默认的情况下bash shell会将下列字符当做字段分隔符:
- 空格
- 制表符
- 换行符
可以在shell脚本中定义IFS的值变更分割符号如IFS=:
在处理代码量较大的脚本时,可能在一个地方需要修改IFS的值,然后忽略这次修改,在
脚本的其他地方继续沿用IFS的默认值。一个可参考的安全实践是在改变IFS之前保存原
来的IFS值,之后再恢复它。
这种技术可以这样实现:
IFS.OLD=$IFS
IFS=$'\n'
<在代码中使用新的IFS值>
IFS=$IFS.OLD
这就保证了在脚本的后续操作中使用的是IFS的默认值
2.3 C语言风格的for循环
在shell脚本中可以通过双括号实现C语言风格的for循环,如:for (( i=1; i <= 10; i++ ))
。
for循环通过定义好的变量(本例中是变量i)来迭代执行这些命令。在每次迭代中,$i变 量包含了for循环中赋予的值。在每次迭代后,循环的迭代过程会作用在变量上,在本例中,变 量增一。
也可以同时迭代两个变量如:for (( a=1, b=10; a <= 10; a++, b-- ))
2.4 while循环
while循环可以视作某种if-then与for循环的混杂体。对while循环设置一个跳出循环条件,如果不符合条件将一直循环下去。设置条件的方式和if-then语句完全一样。需要注意的是当设置条件的时候,需要明确自己是需要一个死循环还是有限循环,并根据设计的目的,添加变量迭代方式。
while循环的基本结果如:
while test command ;do
other commands
done
通过while ture
可以实现代码的死循环,当然即使设置死循环也需要通过break
设置跳出循环的条件。
2.5 until循环
until命令和while命令工作的方式完全相反。until命令要求你指定一个通常返回非零退 出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。 一旦测试命令返回了退出状态码0,循环就结束了。
until的基本格式如:
untile test command;do
other commands
done
2.6 控制循环
你可能会想,一旦启动了循环,就必须苦等到循环完成所有的迭代。并不是这样的。有两个 命令能帮我们控制循环内部的情况:
- break
- continue
break命令可以直接跳出循环,不执行剩余的迭代任务。break默认只跳出一层循环,如果有嵌套循环的存在,需要跳出多层循环,可以通过break n
。n为1,表明跳出的是当前的循环(这也是默认设置)。如果你将 n设为2,break命令就会停止下一级的外部循环。
continue命令可以提前中止某次循环中的命令,但并不会完全终止整个循环。在当前循环中,剩余的命令将不会被执行,而直接进入下一次的循环。