在info bash里的第“6.4 Bash Conditional Expressions”节里开头有一句话说明了shell条件判断的二个机制:
Conditional expressions are used by the `[[' compound command and the
`test' and `[' builtin commands.
机制一:内置(builtin)的函数test(运算符[]),此部分完整的说明,可查看“4.1 Bourne Shell Builtins”
机制二:[[]],条件结构关健字,具体可查看“3.2.4.2 Conditional Constructs”
test跟[]是一回事,只不过一个以函数的形式,一个以成对操作符的形式出现,
test包含6.4节条件表达式的表达形式,
是函数就有参数,test对1、2、3.。。6等多个参数的判断分别进行定义
而[[]],大部分的功能跟[]是一样的,可以简单理解成[]的扩展,但对于参数的判断定义上,比test有更完整的定义,不容易出现[]中的错误
比如在-eq比较的右操作符中,[]要求右操作符不为空,否则报错,返回2,而[[]]则不会:
[root@localhost tmp]# [ 1 -eq $a ]
+ '[' 1 -eq ']'
-bash: [: 1: unary operator expected
[root@localhost tmp]# echo $?
+ echo 2
2
[root@localhost tmp]# [[ 1 -eq $a ]]
+ [[ 1 -eq '' ]]
[root@localhost tmp]# echo $?
+ echo 1
1
这也是很多程序员喜欢用[[]]的原因,不容易出错
相比test的表达能力,[[]]扩展了二个功能
1:pattern match,通配符匹配,采用双等号“==”
2:regex match,正则匹配,采用“=~”运算符号
首先说明下通配符匹配:
先说明一下[]里的==运算,[]也包括==比较,用于字符串相等比较
同样,==号在这里也不允许右操作符为空,否则报错
[root@localhost tmp]# [ "abc" == $a ]
+ '[' abc == ']'
-bash: [: abc: unary operator expected
解决办法是加个引号
[root@localhost tmp]# [ "abc" == "$a" ]
+ '[' abc == '' ']'
而[[]]里的==,在3.2.4.2 里有介绍
When the `==' and `!=' operators are used, the string to the right
of the operator is considered a pattern and matched according to
the rules described below in *Note Pattern Matching::。。。
Any part of the pattern may be quoted
to force it to be matched as a string.
这一段说明至少要注意二点
1:[[]]里的==运算符,把所有右操作符都看做是一个pattern,
==实际上不只是简单字符串比较,而是pattern match,即通配符匹配,具体的规则可以参考
3.5.8.1 Pattern Matching
2:最后一句:引号可以直接定义字符串,在3.5.8.1里也有一句话:The special pattern
characters must be quoted if they are to be matched literally.
即:pattern特殊字符为字符在引号里取消特殊定义
这也就能解释下边的二个例子的差别了:
[root@localhost tmp]# set -x
+ set -x
[root@localhost tmp]# [[ abc == a*c ]]
+ [[ abc == a*c ]]
[root@localhost tmp]# echo $?
+ echo 0
0
[root@localhost tmp]# [[ abc == "a*c" ]]
+ [[ abc == /a/*/c ]]
[root@localhost tmp]# echo $?
+ echo 1
1
另外需要留意下:
在[[里,文档中提到
Word splitting and filename expansion are not
performed on the words between the `[[' and `]]'; tilde expansion,
parameter and variable expansion, arithmetic expansion, command
substitution, process substitution, and quote removal are
performed.
也就是说,在[[里,不进行bash命令解析中的“文字分割Word splitting ” 和 “文件名扩展filename expansion ”
但还是进行了 “~符号扩展,参数和变量扩展,算术扩展,命令替换,进程替换,引号去除”
所以不必担心上边例子中,a*b是否会扩展成目录下的文件名。
至于=~正则匹配,就没有什么特别是的了,右操作数直接定义成一个正则式子即是,这里正则的引号可用可不用(不能用/)
因为在 “quote removal ”环节,对非扩展出来的引号做了去除处理,实际上有加引号与不加引号是一样的结果
[root@localhost tmp]# [[ abc =~ 'ab*c' ]]
+ [[ abc =~ ab*c ]]
[root@localhost tmp]# echo $?
+ echo 0
0
[root@localhost tmp]# [[ abc =~ "ab*c" ]]
+ [[ abc =~ ab*c ]]
[root@localhost tmp]# echo $?
+ echo 0
0
[root@localhost tmp]# [[ abc =~ ab*c ]]
+ [[ abc =~ ab*c ]]
[root@localhost tmp]# echo $?
+ echo 0
0
[root@localhost tmp]# [[ abc =~ /ab*c/ ]]
+ [[ abc =~ /ab*c/ ]]
[root@localhost tmp]# echo $?
+ echo 1
1