為什麼’test -z =‘畢竟不是一個錯誤?
我有一本書說:
“….例如,如果 shell 變數符號包含等號,
看看如果你嘗試測試它的長度為零會發生什麼:
$ echo $symbol = $ test -z "$symbol" sh: test: argument expected
= 運算符的優先級高於 -z 運算符 ….”
但是當我在我的 Ubuntu 上嘗試時(在虛擬機中執行):
jackson@jackson-VirtualBox:/$ symbol="=" jackson@jackson-VirtualBox:/$ echo $symbol = jackson@jackson-VirtualBox:/$ test -z "$symbol" jackson@jackson-VirtualBox:/$
為什麼我的測試命令的結果不是
sh: test:argument expected
?書錯了嗎?
該
test
命令沒有被告知參數是運算符或操作數。例如,shell 程式碼symbol='='; test -z "$symbol"
呼叫test
帶有參數-z
和=
. 由test
命令決定它-z
是一個運算符,並且=
是該運算符的一個操作數。在大多數情況下,最多有一種語法正確的解釋。例如,由於沒有一元後綴運算符,解析兩個參數的唯一方法是第一個參數是一元前綴運算符,第二個參數是它的操作數。因此
test -z =
只能意味著將-z
(is-string-empty) 運算符應用於 string=
。一旦有三個或更多參數,一些邊緣情況就會模棱兩可。例如,
test '(' -a ')'
可以是-a
應用於裸字元串(
和的運算符)
,或-a
括號中的裸字元串。(我想不出帶有三個參數的模棱兩可的解析會給出不同的結果。)該命令的舊實現
test
有錯誤的解析器,它們不接受一些簡短-z =
的明確情況,例如:解析器決定=
第二個位置是二元運算符,然後意識到這個運算符沒有正確的操作數。Sven Mascheck 的 Bourne shell 頁面列出了錯誤的歷史實現test -a =
;這包括 Bourne 實現和古代版本的 ksh。如果給出兩個或三個有效的參數,所有現代實現都會按照您的期望進行。這(以及更多)是POSIX規定的。
該
[
命令具有相同的陷阱,test
因為它是相同的命令,除了需要 a]
作為最後一個參數。一些現代 shell(ksh、bash、zsh)中可用的
[[ … ]]
shell 語法沒有相同的問題,因為它在 shell 內的解析方式不同。[[ -z "$symbol" ]]
被解析為-z
應用於字元串的運算符;即使 of 的值symbol
是等號,該詞=
也不會在命令中按字面意思出現,因此它不能指代運算符=
。除非您正在使用其供應商不支持的古老系統(或者在某些罕見的利基行業中可能仍以某種形式支持),否則您不會遇到
test -z "$symbol"
在現實世界中窒息的外殼。如果一本書提到這一點,那就是嚴重過時了;考慮使用更好的資源。更好的書在第三世界國家可能非常昂貴,但網際網路上有很多免費的東西,其中一些實際上很好。