shell條件表達式小結:test([])與 [[]]

在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

 

 

 

 

 

 

 

 

 

 

 

 

發佈了34 篇原創文章 · 獲贊 8 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章