我經常在使用autotools(autoconf,automake)的項目的構建腳本中看到這種情況。當有人要檢查shell變量的值,他們經常使用這個成語:
if test "x$SHELL_VAR" = "xyes"; then
...
有什麼優勢,這只是檢查像這樣的價值在:
if test $SHELL_VAR = "yes"; then
...
我算起來也必須是我經常看到這個的一些原因,但我無法弄清楚它是什麼。
我經常在使用autotools(autoconf,automake)的項目的構建腳本中看到這種情況。當有人要檢查shell變量的值,他們經常使用這個成語:
if test "x$SHELL_VAR" = "xyes"; then
...
有什麼優勢,這只是檢查像這樣的價值在:
if test $SHELL_VAR = "yes"; then
...
我算起來也必須是我經常看到這個的一些原因,但我無法弄清楚它是什麼。
如果您使用的是一個殼簡單替代和SHELL_VAR
變量不存在(或爲空),那麼您需要注意邊緣情況。下面的轉換會發生:因爲拳頭參數test
不見了
if test $SHELL_VAR = yes; then --> if test = yes; then
if test x$SHELL_VAR = xyes; then --> if test x = xyes; then
其中第一項將產生一個錯誤。第二個沒有這個問題。
你的情況下翻譯如下:
if test "x$SHELL_VAR" = "xyes"; then --> if test "x" = "xyes"; then
可能似乎有點多餘,因爲它具有引號和「×」,但它也將處理與空格的變量,不給作爲兩個參數到test
命令。
另一個原因(空變量除外)與選項處理有關。如果你寫:
if test "$1" = "abc" ; then ...
和$1
具有價值-n
或-z
或任何其他有效的選項爲test
命令,語法是不明確的。前方的x
可防止將前導短跑選作test
的選項。
請記住,這取決於外殼。有些shell(csh
,我認爲)如果環境變量不存在而不是僅僅返回一個空字符串,會很痛苦地抱怨)。
是的,現在看起來很明顯。 – jonner 2008-10-06 13:57:20
我曾經在DOS下做過SHELL_VAR可能未定義的情況。
我相信它是由於
SHELLVAR=$(true)
if test $SHELLVAR = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected
以及
if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected
和
SHELLVAR=" hello"
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep
然而,這通常應該工作
SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi
#<no output>
但是當它在輸出抱怨別的地方,它很難說其抱怨我猜,所以
SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi
作品一樣好,但會更容易調試。
如果你不做「x $ SHELL_VAR」的事情,那麼如果$ SHELL_VAR未定義,你會得到一個關於「=」不是一個monadic操作符或類似的錯誤。
有兩方面的原因,我知道這個約定:
http://tldp.org/LDP/abs/html/comparison-ops.html
在混合測試,甚至引用字符串變量可能是不夠的。如果$ string爲空, [-n「$ string」-o「$ a」=「$ b」]可能會導致某些版本的 Bash出錯。安全的方法是向可能爲空的變量追加一個額外的字符,[「x $ string」!= x -o「x $ a」=「x $ b」](「x's」抵消)。
其次,在其他殼比猛砸,尤其是老年人,喜歡的測試條件「-z」來測試一個空的變量是不存在的,因此,雖然這樣的:
if [ -z "$SOME_VAR" ]; then
echo "this variable is not defined"
fi
將正常工作在BASH中,如果你的目標是跨越各種UNIX環境的可移植性,在這些環境中你不能確定默認shell是Bash,並且它是否支持-z測試條件,那麼使用if [「x $ SOME_VAR 「=」x「],因爲這將始終具有預期的效果。從本質上講,這是一個用於查找空變量的舊shell腳本技巧,儘管存在更簡潔的方法,但它現在仍然用於向後兼容。
另一個沒有人提到的原因是與選項處理有關。如果你寫:
if [ "$1" = "abc" ]; then ...
和$ 1的值爲'-n',測試命令的語法不明確;目前還不清楚你正在測試什麼。前面的'x'可防止前導破折號引起麻煩。
你必須看着真正古老的炮彈找到一個測試命令不支持-n
或-z
;版本7(1978)test
命令包含它們。這並不是無關緊要的 - 一些版本6 UNIX的東西被轉移到了BSD中,但是現在你很難找到任何古老的東西。
正如許多其他人所指出的那樣,在值周圍不使用雙引號是很危險的。事實上,如果文件名可能包含空格(MacOS X和Windows都在某種程度上鼓勵,而且Unix一直支持它,儘管像xargs
這樣的工具使得它更難),那麼你應該把文件名用雙引號括起來你也可以使用它們。除非你負責該值(例如在選項處理過程中,並且在啓動時將該變量設置爲'no',而在命令行中包含標誌時將該變量設置爲'yes'),那麼使用不加引號的變量形式是不安全的直到你證明他們是安全的 - 而且你也可以一直做很多事情。或者如果用戶試圖處理名稱中空白的文件,那麼你的腳本將會非常糟糕地失敗。 (還有其他人物也會擔心 - 例如,反引號也可能相當討厭。)
我建議改爲:
if test "yes" = "$SHELL_VAR"; then
因爲它摒棄了醜陋x
,還解決了https://stackoverflow.com/a/174288/895245提到的問題可-
開始,被解讀爲一種選擇。
請參閱參考[shell腳本在``x $ Variable'``]中的用途「(http://stackoverflow.com/questions/1805663/shell-script-purpose-of-x-in-xvariable/)。這個問題是這個問題的重複。 – 2013-12-29 16:37:16
另請參閱[使用``X``測試空字符串``](http://stackoverflow.com/questions/6852612/bash-test-for-empty-string-with-x)。這個問題實際上也是這個問題的重複,或者涵蓋了大部分相同的理由。這兩個副本都有一些很好的答案。 – 2013-12-29 16:45:51