2008-10-06 90 views
41

我經常在使用autotools(autoconf,automake)的項目的構建腳本中看到這種情況。當有人要檢查shell變量的值,他們經常使用這個成語:

if test "x$SHELL_VAR" = "xyes"; then 
... 

有什麼優勢,這只是檢查像這樣的價值在:

if test $SHELL_VAR = "yes"; then 
... 

我算起來也必須是我經常看到這個的一些原因,但我無法弄清楚它是什麼。

+1

請參閱參考[shell腳本在``x $ Variable'``]中的用途「(http://stackoverflow.com/questions/1805663/shell-script-purpose-of-x-in-xvariable/)。這個問題是這個問題的重複。 – 2013-12-29 16:37:16

+1

另請參閱[使用``X``測試空字符串``](http://stackoverflow.com/questions/6852612/bash-test-for-empty-string-with-x)。這個問題實際上也是這個問題的重複,或者涵蓋了大部分相同的理由。這兩個副本都有一些很好的答案。 – 2013-12-29 16:45:51

回答

67

如果您使用的是一個殼簡單替代和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,我認爲)如果環境變量不存在而不是僅僅返回一個空字符串,會很痛苦地抱怨)。

+0

是的,現在看起來很明顯。 – jonner 2008-10-06 13:57:20

1

我曾經在DOS下做過SHELL_VAR可能未定義的情況。

2

我相信它是由於

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 

作品一樣好,但會更容易調試。

1

如果你不做「x $ SHELL_VAR」的事情,那麼如果$ SHELL_VAR未定義,你會得到一個關於「=」不是一個monadic操作符或類似的錯誤。

9

有兩方面的原因,我知道這個約定:

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腳本技巧,儘管存在更簡潔的方法,但它現在仍然用於向後兼容。

17

另一個沒有人提到的原因是與選項處理有關。如果你寫:

if [ "$1" = "abc" ]; then ... 

和$ 1的值爲'-n',測試命令的語法不明確;目前還不清楚你正在測試什麼。前面的'x'可防止前導破折號引起麻煩。

你必須看着真正古老的炮彈找到一個測試命令不支持-n-z;版本7(1978)test命令包含它們。這並不是無關緊要的 - 一些版本6 UNIX的東西被轉移到了BSD中,但是現在你很難找到任何古老的東西。

正如許多其他人所指出的那樣,在值周圍不使用雙引號是很危險的。事實上,如果文件名可能包含空格(MacOS X和Windows都在某種程度上鼓勵,而且Unix一直支持它,儘管像xargs這樣的工具使得它更難),那麼你應該把文件名用雙引號括起來你也可以使用它們。除非你負責該值(例如在選項處理過程中,並且在啓動時將該變量設置爲'no',而在命令行中包含標誌時將該變量設置爲'yes'),那麼使用不加引號的變量形式是不安全的直到你證明他們是安全的 - 而且你也可以一直做很多事情。或者如果用戶試圖處理名稱中空白的文件,那麼你的腳本將會非常糟糕地失敗。 (還有其他人物也會擔心 - 例如,反引號也可能相當討厭。)