Shell

為什麼’test -z =‘畢竟不是一個錯誤?

  • May 11, 2021

我有一本書說:

“….例如,如果 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"在現實世界中窒息的外殼。如果一本書提到這一點,那就是嚴重過時了;考慮使用更好的資源。更好的書在第三世界國家可能非常昂貴,但網際網路上有很多免費的東西,其中一些實際上很好。

引用自:https://unix.stackexchange.com/questions/645177