bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
test可用於測試表達式,支持測試的范圍包括:字符串比較,算術比較,文件存在性、屬性、類型等判斷。例如,判斷文件是否為空、文件是否存在、是否是目錄、變量是否大於5、字符串是否等於"longshuai"、字符串是否為空等等。在shell中,幾乎所有的判斷都使用test實現。
其中[]完全等價於test,只是寫法不同。雙中括號[[]]基本等價於[],它支持更多的條件表達式,還允許在雙中括號內使用邏輯運算符"&&"、"||"、"!"和"()",但這些使用單中括號都能實現,只不過多寫幾個單中括號而已。單中括號[]無法實現的功能是正則表達式匹配,而[[]]可以實現。因此,在能使用單中括號的情況下,無需考慮使用雙中括號。
test、[ ]以及[[ ]]都使用條件表達式來完成測試。test和[]用法雖簡單,但語法比較復雜,反而是[[]]的語法較為簡單。但不管如何,先解釋條件表達式。
1.1 條件表達式
|
1.2 test和[ ]的用法說明
test和[]的用法非常簡單,但語法較復雜。它們是根據參數的個數來完成測試的,所以測試的結果也依賴於參數的個數。如下所述:
(1).不帶任何參數時,直接返回false。
[root@xuexi ~]# [ ];echo $? 1
(2).只有一個參數時,測試表達式采取的是[ arg ],根據條件表達式的說明,僅當arg為非空時返回true。
[root@xuexi ~]# test haha;echo $? 0
[root@xuexi ~]# test $abcd;echo $? 1
[root@xuexi ~]# test '';echo $? 1
(3).兩個參數時,有幾種情況:
①.第一個參數是單目條件運算符,包括文件類測試(如[ -e file1 ])和[ -n string ]、[ -z string ]。
②.第一個參數是"!"時,則只能是[ ! string ],等價於[ ! -n string ]。因為"!"是對條件表達式取反,所以當string為空時才true。
③第一個參數不是任何有效的操作符。將直接報錯
(4).三個參數時,也有幾種情況:
①.使用了雙目運算符,如[ file1 -nt file2 ],[ init1 -eq int2 ]以及[ string1 != string2 ]。
②.使用了邏輯運算符,如[ string1 -a string2 ]、[ ! -e file ]、[ ! -z string ]、[ ! -n string ]。
③.使用了括號,則只能是[ (string) ]。
(5).四個參數以上時,則處理方法參照上面。如[ ! string1 == string2 ]、[ string1 == string2 -o string1 == string3 ]。
無論參數數量多少個,總的來說還是對條件表達式的測試,所以最重要的還是條件表達式的邏輯結果。
1.3 [[ ]]
[[]]基本等價於[],但有些功能寫法更簡潔,且[[]]提供了[]所不具備的正則表達式匹配。所以,[[]]的功能可以認為是[]和expr命令的相加。
語法格式:
[[ conditional_expression ]]
除了以下特別注明的幾項,其余用法等同[]。
(1).當條件表達式中使用的運算符是"=="或"!="時,該運算符的右邊會被當作pattern被匹配,"=="表示能匹配成功則返回0,"!="則相反。但此時只是通配符匹配,不支持正則表達式匹配。通配符包括:"*"、"?"和"[...]"。
例如:
[root@xuexi ~]# [[ abc == a* ]];echo $? 0 [root@xuexi ~]# [[ abc == a*d ]];echo $? 1
(2).當條件表達式中使用的運算符是"=~"時,該運算符的右邊會被當作正則表達式的pattern被匹配。
例如:
[root@xuexi ~]# [[ abc =~ aa* ]];echo $? 0 [root@xuexi ~]# [[ abc =~ aa.* ]];echo $? 1
(3).除了可以使用邏輯運算符!和(),還可以使用&&、||,分別表示邏輯與和邏輯或,等價於[]的"-a"和"-o"。但是[[]]不再支持"-a"和"-o"。
例如:
[root@xuexi ~]# [[ 3 -eq 3 && 5 -eq 5 ]];echo $? 0
總之,除了模式匹配和正則表達式匹配時需要使用[[]],其余時候建議使用[ ]。
1.4 使用建議
1.無論是[]還是[[]],都建議對其內變量、字符串使用雙引號包圍。換句話說,能做字符串比較的時候,不要用數值比較。
例如:
name="Ma long" [ $name = "Ma long" ]
上面的測試語句將報錯,因為在變量替換階段,$name被替換為Ma long,但它們沒有在引號內,於是進行單詞拆分,這就等價於執行的是[ Ma long = "Ma long" ],顯然這是錯誤的語法。所以,建議加上雙引號:
[ "$name" = "Ma long" ]
2.數值比較時,建議雙方同時加0,避免變量為空時報錯。
例如,變量a為空,下面的表達式是錯誤的。因為它被shell解析后相當於[ -eq 7 ],而這是錯誤的語法。
[root@xuexi ~]# [ $a -eq 7 ] -bash: [: -eq: unary operator expected
采取第一種建議,將$a使用引號包圍的話,還是錯的。因為被shell解析后相當於[ "" -eq 7 ],字符串和數值無法比較。注意這里的報錯和上面的錯誤信息不一樣。
[root@xuexi ~]# [ "$a" -eq 7 ] -bash: [: : integer expression expected
所以最好的方法是將它改為字符串來測試。或者雙方同時加0,由於此處有一方是常量數值,所以只需為變量部分加0即可。
[root@xuexi ~]# [ "$a" = "7" ]
[root@xuexi ~]# [ $((a+0)) -le 8 ]
3.當變量可能為空的時候,強烈建議在變量的基礎上加上其他輔助字符串。看過/etc/init.d下的腳本的人肯定都見過這種用法。
上面的語句雖然能正確測試。其實更安全的方法是采用下面的形式:
[root@xuexi ~]# [ "a$a" = "a7" ] # 判斷a是否為7 [root@xuexi ~]# [ "a$a" = "a" ] # 判斷a是否為空 [root@xuexi ~]# [ ! -z "$a" -a "a$a" = "a7" ] # a不為空且a=7時才為真
4.另外,在[]和[[]]中,每個地方都有空格。這不是書寫建議,而是強制要求的格式。