为什么 'test -z =' 不是一个错误?

为什么 '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

书上有错吗?

答案1

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应用于字符串的运算符;即使 的值symbol是等号,该词=也不会按字面意思出现在命令中,因此它不能引用运算符=

除非您正在使用尚未得到供应商支持的古老系统(或者在某些罕见的利基行业中仍然以某种形式提供支持),否则您不会遇到test -z "$symbol"在现实世界中卡住的 shell。如果一本书提到这一点,那它就已经严重过时了;考虑使用更好的资源。在第三世界国家,更好的书可能贵得令人望而却步,但互联网上有很多免费的东西,其中一些实际上是好书。

相关内容