许多程序要求在shell脚本中的命令间有一些逻辑控制流。
有一类命令会基于变量 值或其他命令的结果等条件使脚本跳过或循环执行命令。这样的命令通常称为结构化命令。
使用if-then语句
结构化命令中,最基本的类型就是if-then语句。格式如下:
if command
then
command
fi
与其他编程语言不同,bash shell的if语句会会运行if行定义的那个命令。如果该命令的退出状态码是0(该命令运行成功),位于then部分的命令就会被执行。反之,如果该命令的推出状态码是其他的值,那then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。
if-then语句还有其他的一种格式:
if command:then
commands
fi
if-then-else语句
在if-then语句中,不管命令是否成功执行,都只有一种选择。为解决这个问题,可以使用if-then-else语句。
格式:
if command
then
commands
else
commands
fi
当if语句中的命令返回退出状态码0时,then部分中的命令会被执行,跟普通的if-then一样。当返回非零退出状态码时,bash shell会执行else部分中的命令。
跟then部分一样。else部分可以包含多条命令。
嵌套if
有时需要检查脚本代码中的多种条件。不用写多个分立的fi-then语句,可以用else部分的替代版本,称作elif。 elif会通过另一个if-then语句来延续else部分:
if comamand1
then
commands
elif command2
then
more commands
fi
elif语句提供了另一个要测试的命令,类似于原始的if语句。如果elif后命令的推出状态码是0,则bash会执行第二个then语句部分的命令。
还可以继续使用多个elif语句串起来,形成一个大的if-thenelif嵌套组合:
if command1
then
command set 1
elif command2
then
command set 2
elif command3
then
command set 3
elfi command4
then
command set 4
fi
每块命令都会根据哪个命令会返回退出状态码0来执行。bash shell 会依次执行if语句,只有第一个返回推出状态码0的语句中的then部分会被执行。这部分可由case命令代替。
tets命令
if-then语句是否能测试跟命令的退出状态码无关的条件。答案是不能。但是,bash shell中有个好用的工具可以帮助你通过if-then语句测试其他条件。test命令提供了在if-then语句中测试不同条件的路径。如果test命令中列出的条件成立,test就会退并返回推出状态码0.这样if-then语句就与其他编程语言中的if-then语句以类似的方式工作了。如果条件不成立,test命令就会推出并返回推出状态码1,这样if-then语句就会失效。
test命令格式
test condition
当test用在if-then语句中时,用法如下:
if test condition
then
commands
fi
bash shell 还提供了另一种在if-then语句中声明test命令的方法:
if 【 condition 】
then
commands
fi
方括号定义了test命令中用到的条件,注意:必须在方括号的左侧与右侧各加一个空格,否则会报错。
test命令会判断3类条件:
数值比较
字符串比较
文件比较
数值比较 (可以用在数字和变量上)
最常见的情形是对两个数值进行比较。如下表
比较 描述
n1 -eq n2 检查n1是否与n2相等
n1 -ge n2 检查n1是否大于或等于n2
n1 -gt n2 检查n1是否大于n2
n1 -le n2 检查n1是否小于等于n2
n1 -lt n2 检查n1是否小于n2
n1 -ne n2 检查n1是否不等于n2
bash shell能处理的数仅有整数。当使用bash计算器时,可以让shell将浮点值作为字符串值存储进一个变量。test命令不能使用浮点值。
字符串比较
test命令还允许比较字符串值。但比较繁琐,如下表:
比较 描述
str1 = str2 检查str1是否和str2相同
str1 != str2 检查str1是否和str2不同
str1 < str2 检查str1是否比str2小
str1 > str2 检查str1是否比str2大
-n str1 检查str1的长度是否非0
-z str1 检查str1的长度是否为0
字符串的相等性
比较字符串的相等性时,test的比较会将所有的标点和大写也考虑在内。
字符串顺序
要测试一个字符串是否比另一个字符串大就变得繁琐了。有两个问题会经常困扰:
1、大于小于符号必须转义,都则shell会把它们当作重定向符号而把字符串值当作文件名
2、大于小于顺序和sort命令所采用的不同
在编写脚本时,第一条肯呢个会导致一个不易察觉的严重问题。一个简单的例子:
#! /bin/bash
# mis-using string comparisons
val1=baseball
val2=hockey
if [ $val1 > $val2 ]
then
echo "$val1 is greater than $val2"
else
echo "$val1 is less than $val2"
fi
这里只用了大于号,没有出现错误,但结果是错的。脚本把大于号解释成了输出重定向。因此,创建了一个名为hockey的文件。由于重定向顺利完成了,test命令返回了推出状态码0,而if语句则以为所有的命令都成功结束了。
要解决这个问题。只需要正确的转义大于号。
# mis-using string comparisons
val1=baseball
val2=hockey
if [ $val1 \> $val2 ]
then
echo "$val1 is greater than $val2"
else
echo "$val1 is less than $val2"
fi
第二个问题更加细微,除非你经常处理大小写字母,否则几乎遇不到。sort命令处理大写字母的方法刚好跟test命令相反。测试如下脚本: #!/bin/bash
# testing string sort order
val1=Testing
val2=testing
if [ $val1 \> $val2 ]
then
echo "$val1 is greater than $val2"
else
echo "$val1 is less than $val2"
fi
¥sort testfile
testing
Testing
在test命令中,大写字母会被当成小于小写字母的。但当你将同样的字符串放进文件中,并用sort命令排序时,小写字母会先出现。这是由于各个命令所使用的排序技术不同造成的。test命令会使用标准的ASCII顺序,sort命令使用系统的本地化语言设置中定义的排序顺序。对于英语,本地化设置指定了在排序顺序中小写字母出现在大写字母前。
字符串大小
-n和-z来检查一个变量是否含有数据。
文件比较
最后一类测试比较可能是shell变成中最强大的也是最经常用到的比较。test命令允许你测试Linux文件系统上文件和目录的状态。如下表:
比较 描述
-d file 检查file是否存在并是一个目录
-e file 检查file是否存在
-f file 检查file是否存在并是一个文件
检查目录
-d file测试会检查指定文件名是否在系统上以目录形式存在。
检查对象是否存在
-e file比较允许你在脚本中使用对象前检查文件或目录对象是否存在。
检查文件
-e比较适合于文件和目录。要确定指定的对象是个文件,你必须用-f比较。
检查是否可读
在尝试从文件中读取数据之前,最好先测试一下能否读文件。可以通过-r比较测试。
检查空文件
-s可以用来检查文件 是否为空,尤其是删除文件时,当-s比较成功时,要特别小心。
检查是否可写
-w比较会判断你是否对文件有可写权限
检查是否可执行
-x比较是一个简便的判断你对某个特定文件是否有执行的权限。虽然大多数命令永不到它,但在shell中运行大量脚本时会很方便。
检查所属关系
-o比较允许你轻松地测试你是否是文件的属主
检查默认属主关系
-G比较会检查文件的默认组,如果它匹配了用户的默认组,那就通过了。但-G只会检查默认组而非用户所属的所有其他组(默认即是groups显示出的第一个组)。
检查文件日期
-nt比较会判定某个文件是否比另一个文件更新。如果问家更新,它会有一个比较近的文件创建日期。-ot会判定某个文件是否比另一个文件更老。如果文件更老,它会有一个更早的创建日期。这在编写安装软件的脚本时非常有用。因为你不想安装一个较老的文件。
复合条件测试
if-then语句允许你使用bool逻辑来组合测试。如下
1、 [ condition1 ] && [ condition2 ];
2、 [ condition1 ] || [ conditoon2 [.
if-then的高级特性
使用双尖括号
test命令只允许你在比较中进行简单的算数操作。双尖括号允许将高级数学表达式放入比较中。格式如下:
(( expression ))
术语expression可以是任意的数字赋值或比较表达式。下表为双尖括号命令符:
符号 描述
val++ 后增
val- - 后减
++val 先增
- -val 先减
! 逻辑求反
~ 位求反
** 幂运算
<< 左位移
>> 右位移
& 位布尔和
| 位布尔或
&& 逻辑和
|| 逻辑或
可以在if语句中使用双尖括号,也可以在脚本中的普通命令里使用来赋值。
使用双方括号
双方括号命令提供了针对字符串比较的高级特性。格式如下:
[[ expression ]]
expression使用了test命令中采用的标准字符串进行比较。但它提供了test命令未提供的一个特性----模式匹配。
在模式匹配中。可以定义一个正则表达式来匹配字符串值。
case命令
解决值多时用多个elif来判定。case命令会检查单个变量列表格式的多个值:
case variable in
pattern1 | pattern2) command1;; (连续两个分号)
pattern3) command2;;
*) default commands;;
esac
case命令会将指定的变量同不同模式进行比较。若变量和模式是匹配的,那么shell会执行为该模式指定的命令。可以通过竖线操作符来分割模式。