我有一本书说:
“......例如,如果 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。如果一本书提到这一点,那它就已经严重过时了;考虑使用更好的资源。在第三世界国家,更好的书可能贵得令人望而却步,但互联网上有很多免费的东西,其中一些实际上是好书。