在 Linux bash shell 中,使用 test 內置命令、[ 內置命令、和 [[ 內置命令進行判斷時,所提供的參數個數會影響判斷結果。
下面以 test 命令為例介紹具體的影響,這些說明也適用於 [ 命令、[[ 命令。
查看 man bash 裡面對 test 命令不同參數個數的判斷結果說明如下:
test and [ evaluate conditional expressions using a set of rules
based on the number of arguments.
0 arguments
----The expression is false.
1 argument
----The expression is true if and only if the argument is not null.
2 arguments
----If the first argument is !, the expression is true if and only if
----the second argument is null. If the first argument is one of the
----unary conditional operators listed above under CONDITIONAL EXPRESSIONS,
----the expression is true if the unary test is true. If the first argument
----is not a valid unary conditional operator, the expression is false.
3 arguments
----The following conditions are applied in the order listed. If the second
----argument is one of the binary conditional operators listed above under
----CONDITIONAL EXPRESSIONS, the result of the expression is the result of
----the binary test using the first and third arguments as operands. If the
----first argument is !, the value is thenegation of the two-argument test
----using the second and third arguments.
針對不同的參數個數,具體舉例說明如下。
0 arguments
$ test; echo $?
1
這裡直接執行 test 命令,不提供任何參數。
參考上面 "0 arguments" 的說明,這種情況下的返回值總是 false。
用 echo $? 打印返回值為 1。
注意 test 命令把 1 作為 false。
1 argument
$ test -n; echo $?
0
$ test -z; echo $?
0
$ test -y; echo $?
0
$ set -x
$ test ""; echo $?;
+ test ''
+ echo 1
1
$ test $dummy; echo $?
+ test
+ echo 1
1
$ set +x
這裡單獨執行 test -n 和 test -z 這兩個命令。
用 echo $? 打印這兩個命令的返回值為 0,都是返回 true。
注意 test 命令把 0 作為 true。
參考上面 "1 argument" 的說明,只提供一個參數時,只要該參數不為空,就會返回 true。
此時的 -n 和 -z 被當作普通的字符串參數,沒被當作 test 命令的操作符。
可以看到執行 test -y 也是返回 true。但是 test 命令並不支持 -y 操作符。
在 help test 的說明中,test STRING 命令在 STRING 不為空時會返回 true,使用的就是隻提供一個參數時的判斷規則。
注意區分上面 test "" 和 test $dummy 的區別。
查看上面打印的調試信息,test "" 經過 bash 擴展,得到的結果是 test ''。
也就是確實有一個參數,這個參數是空字符串。
按照 "1 argument" 的說明,此時返回結果是 false。
由於沒有定義 dummy 變量,test $dummy 經過 bash 擴展,得到的結果只有 test,沒有提供參數。
按照 "0 arguments" 的說明,返回值為 false。
即,雖然 test "" 和 test $dummy 都返回 false,但是它們的參數個數不同,得出結果的原因也不同。
2 arguments
$ test -y go; echo $?
-bash: test: -y: unary operator expected
2
$ test -n go; echo $?
0
$ value=""; set -x
$ test ! -n $value; echo $?
+ test '!' -n
+ echo 1
1
$ test ! -n "$value"; echo $?
+ test '!' -n ''
+ echo 0
0
$ set +x
參考上面 "2 arguments" 的說明,提供兩個參數時,如果第一個參數不是 unary conditional operator,返回結果是 false。
由於 test 命令不支持 -y 操作符,執行 test -y go 命令報錯。
執行 test -n go 命令則會返回 -n 操作符對後面參數的判斷結果。
注意區分上面 test ! -n $value 和 test ! -n "$value" 的區別。
上面將 value 變量設成空字符串,test ! -n $value 經過 bash 擴展,得到的結果是 test '!' -n,提供了兩個參數。
按照 "2 arguments" 的說明,當第一個參數是 ! 時,只有第二個參數是空,才會返回 true。
這裡的第二個參數不是空,所以返回 false。
而 test ! -n "$value" 擴展後的結果是 test '!' -n '',提供了三個參數。
按照 "3 arguments" 說明的規則來進行判斷,會對後面兩個參數的判斷結果進行取反。這裡最終返回 true。
3 arguments
$ test -n go on
-bash: test: go: binary operator expected
在這個測試例子中,在 test -n 後面的字符串包含空格,又沒有用雙引號把字符串括起來,那麼參數個數會變多。
這裡提供了三個參數,-n 也是一個參數。
參考上面 "3 arguments" 的說明,提供三個參數時,預期第二個參數是 binary conditional operators。
由於這裡沒有提供,執行報錯,提示 "go: binary operator expected"。也就是所給的第二個參數 "go" 預期是一個 "binary operator",但它不是。
總結
總的來說,不加雙引號來引用變量值,當參數值為空、或者包含空格時,會導致 test 命令的參數個數發生變化。之後按照不同參數個數的判斷規則進行處理,可能會導致不預期的結果。
結合上面幾個例子可以看到,用雙引號把變量值括起來,只會得到一個參數,保持參數個數不變,可以避免很多異常。
閱讀更多 霜魚片 的文章