![高性能Linux服务器运维实战:shell编程、监控告警、性能优化与实战案例](https://wfqqreader-1252317822.image.myqcloud.com/cover/769/33643769/b_33643769.jpg)
2.2 运算符、测试操作符以及if语句
2.2.1 算数运算符
在Linux shell中,算术运算符包括:+(加运算)、-(减运算)、*(乘运算)、/(除运算)、%(取余运算)和**(幂运算),这些算术运算符的举例及其结果见表2-8。
表2-8 算数运算符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_01.jpg?sign=1739560550-VnRGILEuyuS50zPsRnv5IgxdGGAxgwe6-0-ce224948594d2497dcbb62a17a9a2a63)
1.算术运算扩展
算术运算扩展可以对算术表达式求值并替换成所求得的值。它的格式是:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_02.jpg?sign=1739560550-RApIWRMw1xjhqwQMtOaUYkKvWk1wWzKh-0-6fba0fb756474314c1d8618f055d8d4f)
需要注意的是,算术运算扩展中的运算数只能是整数,算术运算扩展不能对浮点数进行算术运算,注意上面两种方式的写法,下面给几个例子,以加深理解,先定义一个变量num1:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_03.jpg?sign=1739560550-6WcXLI31vFDotOKFinh4GQPXe3L6jkHh-0-f17298bf2b794870a5140610f6ae361c)
从输出可知,num1执行了中括号中的算数表达式,接着,再来看一个变量定义方式:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_04.jpg?sign=1739560550-ps9URm75c6KeQyc7BDKB0ljXsMSEEThF-0-edf5dea5c86db1b70cd0478802c76f89)
这个定义方式是算数表达式中有变量,由于表达式中$num1变量为5,所以这个表达式的结果应该为5*2-3=7:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_05.jpg?sign=1739560550-K6FLByox7gcOaiTTJlfLai6yjFSLowJX-0-18c12e4f5ea30dd123de01452027fa15)
继续看下面这个算数表达式定义方式:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_06.jpg?sign=1739560550-ueBF000KHvxPfUpbqLz73RPKOxhPqq8n-0-3517114feb604f760ffc1dee014222ca)
由此可知,双小括号中还可以是一个完整的算数表达式,下面这个写法也是可以的:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_07.jpg?sign=1739560550-M0jeed5dVSpP8S42d3PQNHkauildWWOT-0-9a4b23921e7af78d3c7ed31bb014a592)
还有下面这个写法:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_08.jpg?sign=1739560550-xxk9OWxO6SbuFl84DCyTL5gPoUf8oUmd-0-08951a6dd3a6e118a9d76a263814a6bb)
在$(( ))中的变量名称,也可在其前面加$符号来替换,也可以不用,例如:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/62_09.jpg?sign=1739560550-QYyGQWUwfzgMeb9tSafueUkBRMzIfMtn-0-1e4c1adc29534f2c1907a60a40d84f89)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/63_01.jpg?sign=1739560550-mM3ROn2wvhM3J0k3QF4UZUwQsk3cVNBe-0-1ee06808bea3fbc14ec22ea66bea9c67)
由此可知,echo $(( $a+$b*$c))和echo $(( a+b*c ))的结果是一样的。在用$[???]、$((???)) 进行整数运算时,括号内变量前的$符号可以省略也可加上。最后,单纯用 (( )) 也可重定义变量值,例如:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/63_02.jpg?sign=1739560550-aRKNHqDXWH1yBiAEuqg2M3YosjqKWcAe-0-0d4fe06350f58bdab1b950a7b281d971)
则$a重定义为6
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/63_03.jpg?sign=1739560550-h5wWeR79d5fanjUaJOdfAik9q8wvgoSG-0-994023bccf51b3dca29635709bd6047c)
则a=4
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/63_04.jpg?sign=1739560550-c4r1IIsFQLi7Wbs2HFLhVVRCewX4wUuj-0-4be51be8e7d2f7c4dffd67fb407e7d36)
会得到0 (true) 的返回值。
注意,在使用 ${???}、$(???)、$[???]和$((???)) 时它们之间的区别和不同用法。${???}用来定义变量,而$(???)用作命令替换,$[???]和$((???))用作整数运算。
2.算术运算指令expr
expr命令可以实现数值运算、数值或字符串比较、字符串匹配、字符串提取、字符串长度计算等功能。它还具有几个特殊功能,判断变量或参数是否为整数、是否为空、是否为0等。这里重点看expr的整数运算方式,举例如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/63_05.jpg?sign=1739560550-Z5SG8EkdepGT9K1fopVZNhNSpVHAv0Iw-0-c75a685ad289021c3c7e3d9e87dbdde2)
上面例子中,如果有乘法符号,则乘法符号必须被转义,如果有括号,则括号必须被转义,另外,表达式中参数与操作符必须以空格分开。
3.算术运算指令let
let命令是Bash的内部命令,它同样可以用于算术表达式的求值。let命令按照从左到右的顺序将提供给它的每一个参数进行算术运算。当最后一个参数的求值结果为真时,let命令返回退出码0,否则返回1。
let命令的功能与算术运算扩展基本相同。但是let语句要求默认情况下在任何操作符的两边不能含有空格,即所有算术表达式要连接在一起。如要在算术表达式中使用空格,就必须使用双引号将表达式括起来。
看下面几个例子,操作过程如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/64_01.jpg?sign=1739560550-pgEZKPdysWv0BpelShky8wNevhgSfEY9-0-13feabb7feef4d35a70423312a13c8a9)
注意,赋值符号和运算符两边不能留空格。如果将字符串赋值给一个整型变量时,则变量的值为0,如果变量的值是字符串,则进行算术运算时设为0。再看一个例子,操作过程如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/64_02.jpg?sign=1739560550-1bVEySSG952BKDfsk5cuCOBjFVpz4OuD-0-d05b0f61c9756d1ad7d77c1d2e599d38)
如果算数表达式中有空格,需要用引号忽略空格的特殊含义,在用let命令进行算术运算时,最好加双引号。
4.自增自减运算符
自增自减操作符主要包括前置自增(++variable)、前置自减(--variable)、后置自增(variable++)和后置自减(variable--)。
前置操作首先改变变量的值(++用于给变量加1,--用于给变量减1),然后再将改变的变量值交给表达式使用。后置操作则是在表达式使用后再改变变量的值。
要特别注意自增自减操作符的操作元只能是变量,不能是常数或表达式,且该变量值必须为整数型,例如,++1、(num+2)++都是不合法的。
2.2.2 条件测试与条件测试操作符
1.条件测试
条件测试可以根据某个特定条件是否满足,来选择执行相应的任务。Bash中允许测试两种类型的条件:命令成功或失败、表达式为真或假。
任何一种测试中,都要有退出状态(返回值),退出状态为0表示命令成功或表达式为真,非0则表示命令失败或表达式为假。状态变量$?中保存了命令退出状态的值,例如:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/64_03.jpg?sign=1739560550-1d2z95QURAjedUUCcky9mY9icBdD9VV5-0-b50f5afc7afca125785e0589a4233aac)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/65_01.jpg?sign=1739560550-vCSgox9U0nXI8S34Ayl99cOuQIMbEOUT-0-0c995ac7fc11a600a72b7cbfd7d05d43)
第1个grep命令,查看当前用户是否在 /etc/passwd文件中,执行后有输出结果,说明命令执行成功,所以状态变量返回0。第2个grep查询hello字符是否在 /etc/passwd文件中,命令执行完成后,没有输出,所以状态变量返回1。
2.test与条件测试语句
test命令在shell中主要用于条件测试,如果条件为真,则返回一个0值。如果表达式不为真,则返回一个大于0的值,也可以将其称为假值。test命令支持测试的范围包括:字符串比较、算术比较、文件是否存在、文件属性和类型判断等。例如,判断文件是否为空、文件是否存在、是否是目录、变量是否大于3、字符串是否等于iivey、字符串是否为空等。
在shell中,几乎所有的判断都使用test命令实现。但是,实际shell编程中,使用test命令并不多,更多使用的是单中括号[ ]和双中括号[[ ]],因此,shell中条件测试的语法格式常用的有如下三个。
➢ 格式1:test<测试表达式>。
➢ 格式2:[<测试表达式>]。
➢ 格式3:[[<测试表达式>]](bash 2.x版本以上)。
其中:
格式1和格式2是等价的,也就是说[ ]完全等价于test,只是写法不同。格式3是扩展的test命令。双中括号[[ ]]基本等价于[ ],但它支持更多的条件表达式,例如,双中括号内可以使用逻辑运算符&&、||、!和(),但在[ ]中不能使用,此外,单中括号[ ]无法实现正则表达式匹配,而[[ ]]却可以实现正则表达式匹配。
需要特别注意的是,[和[[之后的字符必须为空格,]和]]之前的字符必须为空格,也就是说单、双中括号内左右两边必须有空格。
要对整数进行关系运算还可以使用(())进行测试。但是需要注意双小括号和双中括号在使用上的区别。
条件测试表达式中可用的操作符有很多,常用的有以下几种。
➢ 字符串测试操作符。
➢ 整数比较操作符。
➢ 逻辑运算符。
➢ 文件测试操作符。
下面先看看内置测试命令test的基本用法,举例说明。
(1)用test命令来测试表达式的值
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/65_02.jpg?sign=1739560550-8naJWGDNKvv4TG9uryOmSxs2kEug9PDN-0-a46c2c96ffbf45310e0643d99fffbeaa)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/66_01.jpg?sign=1739560550-jQKW83aEXkiNfczwEtl9SK7SkjXHOfXm-0-591169a192007263b213d03c42449edf)
(2)用方括号代替test命令
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/66_02.jpg?sign=1739560550-bRJw7fu1TyoCgZ9oClEUUXyQc1CkJCYN-0-01f3e4b65c685eac99a14f529c9510aa)
注意,方括号前后都要留空格,不然shell会报错,这不是书写建议,而是强制要求的格式。
3.方括号测试表达式
[[ ]]基本等价于[ ],但有些功能写法更简洁,且[[ ]]提供了[ ]所不具备的正则表达式匹配功能。所以,[[ ]]的功能可以认为是[ ]和expr命令的相加。
语法格式:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/66_03.jpg?sign=1739560550-EYvhZF1ZK9z59LUSHyB3WeJ2uIonsZhc-0-adb9fd9725cadda9747e02c437221662)
2.x版本以上的Bash中可以用双方括号来测试表达式的值,此时可以使用通配符进行模式匹配,例如:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/66_04.jpg?sign=1739560550-hRtgcTW4w0cStBATv6W0U4M10QfGh7bN-0-b69765b6d9f28608ec4a020330dcd0b9)
这个测试状态返回1,表示结果为假,这是因为在单中括号中,不支持通配符,继续看下面这个测试过程:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/66_05.jpg?sign=1739560550-3WC2dsELTardJKaSRlhGRPPvMI1MlnsB-0-13c74550c21791fd711960b6b4614e76)
从这个输出可以看出,单中括号改为双中括号后,这个表达式匹配成功,返回结果为真。
4.字符串测试操作符
字符串测试操作符的作用有:比较两个字符串是否相同、字符串的长度是否为零、字符串是否为NULL等。
常用的字符串测试操作符见表2-9。
表2-9 字符串测试操作符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/67_01.jpg?sign=1739560550-owMHULAJYYkqDdR033ANu2I3lXx1tHY8-0-c9a3e6149f37b4553c07d03c262b866d)
单、双中括号操作符两边必须留空格!字符串大小比较是按从左到右对应字符的ASCII码进行比较。
看下面这个例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/67_02.jpg?sign=1739560550-G7IKSDO9FTzEr6v2N9CIp33u5fmHaAqY-0-b9edff3acb86d0b09c0254f72969b35b)
上面这个例子判断$name字符串长度是否为0,显然不为0,那么状态码返回1是正确的,继续看下面的例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/67_03.jpg?sign=1739560550-VJg6GkLhTmX3huytBuWdxRLn2nVmxyWR-0-9b3a7be66616d69486112f714ff52a9c)
上面这个例子定义了name2变量,判断name1是否等于name2,显然不相等,所以状态码返回1是正确的,继续下面的操作:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/67_04.jpg?sign=1739560550-JAepK9NFIGz9HvyhM93Sn7kU15ZUWcOA-0-ee9f591d9fe2641671dc186135298137)
上面这个例子重新赋值name为"Tom sql",注意,这个字符串中有空格,然后再次进行字符串长度是否为0的判断时,出错了,原因就是字符串中含有空格,如何解决呢?操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/67_05.jpg?sign=1739560550-45Ep333xis4SjT6IjUKFePFsJpTXQQTt-0-6841e56e44de7a07993fea1f6c54aa12)
上面这个例子将变量$name加上了双引号,命令执行就恢复正常了,输出结果也正确了。继续看下面操作:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/68_01.jpg?sign=1739560550-AnCrWDp6mrUGXSxnAvDQr96zlSRrqBTF-0-ba57e3e4457603733485cbfd5c005a2a)
上面这个命令是新增了一个变量name2,并赋值,注意name2的值也包含空格,接着进行name和name2是否相等的判断,结果又出错了,解决方法如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/68_02.jpg?sign=1739560550-2u2KJusMsCEwWegArfORGaAqg42IEw5P-0-5c10abd94a045b9bb8d4afa01b5890f1)
从上面两个修改后的指令可以看出,将变量都加上双引号后,就恢复正常了,可见,双引号在变量引用进行条件判断的时候非常重要。
最后,总结一下注意事项。首先,字符串或字符串变量比较都要加双引号之后再比较。其次,字符串或字符串变量的比较,比较符号两端最好都有空格。最后,=比较两个字符串是否相同,与==等价,如["$a"="$b"],其中$a这样的变量最好用双引号引起来,因为如果中间有空格、星号等特殊符号时就可能会出错,更好的办法就是["${a}"="${b}"]。
shell中很多情况下需要对字符串是否为空值进行检查,检查方式有如下几种。
➢ ["$name"=""]。
➢ [-z"$name"]。
➢ [ !"$name"]。
➢ ["X${name}"="X"]。
上面4种方式都可以来检查变量name是否为空值,其中第2种方式使用比较多。当然,也有检查变量是否为非空值的场景,检查方式有如下几种。
➢ ["$name"!=""]。
➢ [-n"$name"]。
➢ ["$name"]。
➢ ["X${name}"!="X"]。
在具体的shell编写中可灵活使用,其中第三种使用最多。
5.逻辑测试操作符
逻辑测试操作符主要包括逻辑非、逻辑与、逻辑或,具体描述见表2-10。
表2-10 逻辑测试操作符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/68_03.jpg?sign=1739560550-DO5vAHyYoFg7l1nTf2azkKZgpi7RlST2-0-d9e64f052e3326f1ddcd2bcfdd74df4d)
注意在逻辑测试中,-a、-o的含义,一个是逻辑与,一个是逻辑或。下面来看几个例子,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/69_01.jpg?sign=1739560550-mERdBJiO8hAE79zKMIEMgXkVaVKWK162-0-7b7d92c6f57ecb257030e7a4a6898bbd)
这个中括号中的表达式是测试变量x是否等于1,同时,字符串变量name长度是否非空,两个条件同时满足,那么结果为真,返回0,否则返回非0。继续看下面这个例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/69_02.jpg?sign=1739560550-eiIHM0v8hWI3k6O0vUtzFd2piJU8ywFA-0-4e5efc97bde096b1d0591c16471b032a)
这个逻辑测试无法执行,原因是不能在中括号中随意添加小括号。另外,还可以使用匹配模式的逻辑测试操作符,见表2-11。
表2-11 匹配模式的逻辑测试操作符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/69_03.jpg?sign=1739560550-spoIWHSP8CSfWlUC2ny3AwTdFsXCZfAa-0-cd6601de4d53e0e257f63f5f8350fe2b)
注意,匹配模式的逻辑测试操作符只能在双中括号中,而不能在单中括号,来看个例子,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/69_04.jpg?sign=1739560550-XPHAZWKQXLSi7B8xIsrF2ippkoZvrua3-0-f1f2feb609109338746db13919202750)
可以看出,第2个逻辑测试出错了,因为单中括号不支持模式匹配。而在第1个逻辑测试表达式中,使用了通配符?,并且执行结果正常。
6.整数测试操作符
整数测试,即比较大小,这个很好理解,在shell编程中也使用最多。首先看一下常用的整数测试操作符,见表2-12。
表2-12 整数测试操作符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/69_05.jpg?sign=1739560550-h3JJfv2YvhlJsSRndEd6Trbz0K0RXcKt-0-74f235097545d2cd67518e9dbfae6de1)
(续)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/70_01.jpg?sign=1739560550-24R1GyMcDDqIwrA2SAsySm73vHoHQVgd-0-d4b743fcfd9a0bea8001ca42cbba9bad)
这里用到了整数测试的几个操作符,分别是eq、ne、gt、ge、le和lt,注意它们各自代表的含义,另外注意,整数测试操作符中,单、双中括号对应的操作符两边也必须留空格,看下面这个例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/70_02.jpg?sign=1739560550-yAsu1y0I9QNuH5kXx5ayikwvzfjX1lvG-0-53253db33e095a60a755bda315d61b81)
上面这个例子是对变量x是否等于1进行判断,所以返回结果为真。再看下面例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/70_03.jpg?sign=1739560550-VjDDgVdYT1fdw3lRvzgqcTH09fZ7JhjW-0-3c8f5a22560e13ad0bbde69adaf2271d)
这个返回结果为假,原因在于变量x的值为字符串,将eq用于字符串和整数的比较,肯定是错误的,因此上面这个例子的写法是错误的,必须将变量x赋值为整数,不能是字符串。
除了使用单、双中括号进行整数的测试,还可以使用双小括号进行整数的测试。双小括号常用的整数测试操作符见表2-13。
表2-13 双小括号的整数测试操作符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/70_04.jpg?sign=1739560550-kDeUIAm20BLgXercC7lAeUrNsguZsv9D-0-7a8faa9b638539792e289a5c2c032959)
这里双小括号中整数测试操作符使用了==、!=、>、>=、<、<=等操作符,这些操作符只能用于整数测试,注意与单、双中括号中使用的操作符不同。另外,双小括号操作符两边的空格可省略。其实,==、!=、>、<操作符也可以用在单、双中括号中,只不过>和<的符号在[]中使用需要转义,对于数据不转义的结果未必会报错,但是结果可能会出错,看下面这个例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/70_05.jpg?sign=1739560550-VkifPwYly037ZXdL6cppfvJ9OFOULYGD-0-6f6a2abdf48d105c8ad371aaae52d1ca)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/71_01.jpg?sign=1739560550-5bbXGuMIu03InjmRJJrw9aci4970LNIe-0-85d909f01d24d79e07fc2f1dc88e78e1)
从上面两个命令可以看出,=和!=在[ ]和[[ ]]中使用不需要转义,继续看下面例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/71_02.jpg?sign=1739560550-wN3omuA4H4o5SPRGDloD85LbS5V4HYvH-0-4998dd484d41ddfa7bba1e680c811326)
上面这个例子中,执行没有报错,但是结果是错误的,因为a明显是小于b的,但结果为真,因此这种写法有问题,继续看下面的例子:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/71_03.jpg?sign=1739560550-qdIdXZd5WZr81OX9o1CudiwcBE4ThlYv-0-194b6e9b1e8af30a2a88633b09f643e1)
上面这个例子中,在>前加上了转义字符,可以看到结果正确了。
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/71_04.jpg?sign=1739560550-c8ODKSi9sM07lq8bjcErQLOFrNYi9VbS-0-39ffd886f2c7d274f4c0dab10f9009a3)
同理,上面这个例子中,在<前加上转义字符,可以看到结果也是正确的。
7.文件测试操作符
文件测试操作符用来测试文件是否存在、文件属性、访问权限等场景,常用文件测试操作符见表2-14。
表2-14 文件测试操作符与含义
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/71_05.jpg?sign=1739560550-qcPkoVlh8htpWMrdJKEiTJmnNdB9Ge9s-0-e27d99b728112c623e184996c74088bb)
下来来看几个例子,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/71_06.jpg?sign=1739560550-UdUI89gQilZ13CXhOtoqGrxjz0dYEHsX-0-38f3c7fa0a1f8cdfed7776d5b5ea9932)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/72_01.jpg?sign=1739560550-K3DrZ9S7ovTfloRGQCztIko577HTn5ht-0-2f0776af0ccb3c62dfb2fc8201c5fefa)
8.条件测试举例
下面通过几个例子来综合掌握一些添加测试的使用环境和注意事项。首先看第1个例子,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/72_02.jpg?sign=1739560550-XShO258khHOX6sdRYhlKXnvGuxItBsV6-0-82a6e97f91c96a9493cff0f3139710aa)
这是对逻辑与的功能测试,需要左右两边两个条件同时满足,才能返回真。
继续看第2个例子,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/72_03.jpg?sign=1739560550-UKnDaoACl4BzbZ0SZy7dDqbSOgjbtJ6h-0-e03fd065d12ab88f60a5d31fe4b584a4)
从上面操作过程可知,(())中不能使用模式匹配,要使用[[ ]],可以通过上面最后一个命令实现,注意,最后一个命令中的&&并非逻辑运算符,而是命令聚合符号。
然后看第3个例子,这个例子是字符串测试,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/72_04.jpg?sign=1739560550-DsDrvG95ygGXwNU64xk64yyZDU8FNw8D-0-093a1efe8329d8fb5d157671a28a006e)
第1个命令中,是判断name变量长度是否为0,从给出的赋值可知name变量不为0,所以结果为假,返回1。第2个命令是判断name和name2两个字符串是否相等,很显然,两个字符串变量不相等,所以结果为假,返回1。
这里需要注意,如果是字符串变量做比较,变量最好用双中引号括起来。还需要注意的是,方括号前后要留空格,[ ]内不能使用通配符。
继续看第4个例子,操作过程如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/73_01.jpg?sign=1739560550-pzZ2TsFpk4ZFeGTOf0mXb7edBc8nN7XK-0-37430dd4d7bbede80851858b4c134c23)
上面两个命令是字符串测试,通过单、双中括号判断变量a不等于b,显然结果为真,接着看第5个例子,操作过程如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/73_02.jpg?sign=1739560550-iYASgfjtOfqtrTog8lrRx04Vg41SmgmH-0-34db9c76546c1ee0fcf78789d24b954c)
上面两个命令是整数测试,通过单、双中括号判断变量n是否大于变量m,显然,n小于m,结果为假。继续看下面操作:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/73_03.jpg?sign=1739560550-Yf1xXLLAg18PcviDLe0aQEkFMj3AnXM3-0-45941b5f149b78ea3a6c18423f8ca04b)
上面两个命令也是整数测试,通过双小括号判断变量n是否大于变量m,结果都返回正确,这里重点讲解的是双小括号中可以加上变量前缀$,也可以省略$,对执行结果不影响。再看看双中括号中省略$的执行结果,操作如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/73_04.jpg?sign=1739560550-tp9DXztFbe3ncgFYc8sDblsjBTv6ShFq-0-780f3024bd11ad861640b51d65bdd1ae)
去掉$后,变成了字符串测试大小,因此这里比较的是n和m对应字符的ASCII码的大小,显然n大于m,所以结果为真。
最后,再来看第6个例子,紧接着上面的操作,再来看下面这组操作:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/73_05.jpg?sign=1739560550-o1uE8nzGEo99cusqyepZd4wj0fO862ro-0-b6b0d1c888bfa336ebdce45976999fef)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/74_01.jpg?sign=1739560550-yKfQplL5nFiHP7D61vMWwZCBEzFdE0hq-0-cbd9a96fdddd669c3903c440019ef6f2)
这个操作中主要看&&和||两个操作符,如果前面的条件测试操作返回真,那么结果就返回T,否则,结果返回F。注意&&和||两个操作符的用法。
2.2.3 if/else判断结构
if判断是shell编程中使用频率最高的语法结构。下面看看shell中if判断的几种常用结构和执行的逻辑。
1.简单if结构
最简单的if执行结构如下所示:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/74_02.jpg?sign=1739560550-o5lq2Bm7xYSKgxso7LCd3llzHxi95cRQ-0-cbbfd7f0f94d41f4e9da80db418e3427)
在使用这种简单if结构时,要特别注意测试条件后如果没有;,则then语句要换行,否则会产生不必要的错误。如果if和then处于同一行,则必须用;,来看下面这个脚本:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/74_03.jpg?sign=1739560550-uE9Zv2gecSAvo8oVR2UQIq42yOi7Yk9p-0-23ad4977321f0113026783bfc51895e7)
在这个脚本中,if的条件判断部分使用了扩展的test语句[[…]],[[ ]]中可以使用正则表达式进行条件匹配,脚本功能是读取输入内容,如果输入为Y、y、Maybe或maybe,那么if条件成立,将执行echo "Glad to hear it.",也就是返回Glad to hear it.信息。
执行这个shell脚本,结果如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/74_04.jpg?sign=1739560550-NKTzS82ZiCRe8GQQGAfCk51xaFnv49xr-0-65b8836e933a7316ad682708221873f2)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/75_01.jpg?sign=1739560550-RWw6KEE6Ss8i1uPjINvHRpYPFfrMbeVb-0-406ab20e5fa6af77b0884784ca7a1545)
可以看出,脚本就是按照预期执行的,当输入的内容不满足if条件的时候,直接退出脚本,不执行任何操作。
2.if/else结构
if/else结构也是经常使用的,这个结构是双向选择语句,当用户执行脚本时如果不满足if后的表达式,就会执行else后的命令,所以有很好的交互性。其结构为:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/75_02.jpg?sign=1739560550-2FvmUoTzqm2nfHVn43uEkRyL8JAzOXWs-0-fb270eca61c1027c4a0839cdf89ed5fc)
来看下面这个脚本onlineuser.sh,内容如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/75_03.jpg?sign=1739560550-LuPqWjrB8F9DVT9eMNh9ObQByNqJqYGR-0-a47f229e04bdf833a28132d95251240f)
这个脚本是读取输入参数,输入参数是Linux的某个用户,如果给出了用户,那么将执行嵌套的那个if/else语句,否则,返回信息Usage:onlineuser.sh<username>。
注意,这个脚本中嵌套了一个if/else语句,也就是满足[ $# -eq 1 ]条件后,就会执行里面的if/else嵌套语句(注意,$#代表输入参数的个数)。这个嵌套语句中仍是通过if判断who|grep^$1>/dev/null这个命令的执行结果状态,也就是echo$?,如果返回0,则满足要求,就显示$1 is active.,这里面的$1会替换成执行脚本时给出的参数;否则,将返回$1 is not active.信息,$1仍然会被替换为执行脚本时给出的参数。
执行这个shell脚本,结果如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/75_04.jpg?sign=1739560550-QVXK8FWFpdyYxCacfYYPMjnBYEVXTe2v-0-29733f667174532697124f5aee7f2e69)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/76_01.jpg?sign=1739560550-YaK3XT3NWYxfi4A6k3pRkastCEEy8lda-0-496c03ca65b9a97dac39b75c272fd625)
可以看出,脚本就是按照预期执行的,脚本后面的root、nobody都是Linux系统下的用户。
3.if语句执行流程
if语句主要有两种结构,分别是单分支if和双分支if/else,下面分两种情况看看if语句的执行流程。
(1)单分支if
此结构主要的应用环境是当“条件成立”时执行相应的操作,如图2-1所示。
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/76_02.jpg?sign=1739560550-n3k9SGNbTrLCztsQ3Z1vQduvSX3H0opN-0-9f815012b592867d4e9ce36f782940f1)
图2-1 单分支if结果
(2)双分支if/else
此结构主要的应用环境是当“条件成立”“条件不成立”时分别执行不同操作,如图2-2所示。
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/76_03.jpg?sign=1739560550-KpLMH6xIAc1LwSaehgZ5Ck0URA4BmphC-0-6146bc60b89b234e7ae54e67af2c65c6)
图2-2 双分支if/else结构
4.if/elif/else结构
if/elif/else结构用于更复杂的判断,它针对多个条件执行不同操作,语法结构如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/76_04.jpg?sign=1739560550-t3WEV1Hhr6yeIIaCmPlIq7IrzdZJYERj-0-f3ef97e3c2d9c06bb0517e296f28d6fc)
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/77_01.jpg?sign=1739560550-RIb6lGBOUiyM7oWUZgbmrCVw1ssDLDyo-0-ccf7106f10d9818edaf52d039f4cd82e)
if/elif/else语句稍微有些复杂,下面通过一张图看看它的执行流程,如图2-3所示。
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/77_02.jpg?sign=1739560550-mZK284Nly0Wrwj30D3waMGmkSxY5u8J7-0-5f06a092ff1201d791f4d96b306ef80e)
图2-3 多分支if/elif/else结构
要深入理解这个结构,先来看下面这个脚本askage.sh,内容如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/77_03.jpg?sign=1739560550-GSsVjsK4QhnWguzKuCwH7PhUz5jDwOKZ-0-9ffbd37f770111ee2fd3b32d364907d3)
这个脚本稍微复杂一些,首先通过read读取从键盘上的输入,将输入值赋给age变量,下面接着有一个age范围的判断,如果输入的age小于0或大于120岁,那么将给出超过范围的提示。
使用多分支if语句对输入的各个年龄段进行判断。这里给出了5个if分支,注意每个分支判断相当于整数测试。这里使用双小括号来进行整数判断,当然也可以使用单、双中括号,不过建议在进行整数判断时,使用双小括号,因为双小括号书写简单还不易出错。
执行这个shell脚本,结果如下:
![](https://epubservercos.yuewen.com/680E1C/17977546608668706/epubprivate/OEBPS/Images/78_01.jpg?sign=1739560550-6EVIybwKNovRDksoNWuIcHLfhqX1CcJM-0-08a587733bc3253f4d87447af994ab4d)
从输出结果可以看出,shell执行正常,当输入130的时候,给出了Out of range!的提示。其他输入和输出,都跟shell脚本完全对应。
5.使用If/else判断注意事项
在使用if/else时候,有一些需要特别注意的事项,总结如下。
➢ if语句必须以if开头,以fi结束。
➢ elif可以有任意多个(0个或多个)。
➢ else最多只能有一个(0个或1个)。
➢ commands为可执行语句块,如果为空,需使用shell提供的空命令:,即冒号。该命令不做任何事情,只返回一个退出状态0。
➢ expr通常为条件测试表达式;也可以是多个命令,以最后一个命令的退出状态为条件值。
➢ if语句可以嵌套使用。