这是一个非常模糊的极端情况,可能会考虑如何[
定义内置测试的错误。但是,它确实与[
许多系统上可用的实际二进制文件的行为相匹配。据我所知道的,它只影响某些情况下以及具有相匹配的值的变量[
运营商一样(
,!
,=
,-e
,等。
让我解释一下为什么以及如何在Bash和POSIX Shell中解决它。
说明:
考虑以下:
x="("
[ "$x" = "(" ] && echo yes || echo no
没问题; 上面没有错误,并输出yes
。这就是我们期望工作的方式。您可以根据需要将比较字符串更改为'1'
,并将的值更改x
为预期值。
请注意,实际的/usr/bin/[
二进制文件的行为方式相同。如果您运行例如'/usr/bin/[' '(' = '(' ']'
,则没有错误,因为程序可以检测到参数由单个字符串比较操作组成。
该错误在我们和第二个表达式出现时发生。第二表达式是什么都没有关系,只要它是有效的即可。例如,
[ '1' = '1' ] && echo yes || echo no
输出yes
,显然是有效的表达式;但是,如果我们将两者结合起来,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
当且仅当x
为(
或时,Bash拒绝该表达式!
。
如果我们使用实际[
程序运行上述程序,即
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
该错误是可以理解的:由于外壳程序执行变量替换,因此/usr/bin/[
二进制仅接收参数(
=
(
-a
1
=
1
和终止符]
,因此可以理解,无法解析开括号是否开始子表达式,并且 涉及到和操作。当然,可以将其解析为两个字符串比较,但是如果将其应用于带有括号的子表达式的正确表达式,可能会产生贪婪的感觉,这可能会引起问题。
实际上,问题在于[
内置的shell 行为相同,就像x
在检查表达式之前扩展了value 一样。
(这些歧义性以及其他与变量扩展有关的歧义是实施Bash的很大原因,现在建议[[ ... ]]
改为使用测试表达式。)
解决方法很简单,通常在使用旧版sh
Shell的脚本中看到。您通常x
在字符串(两个要比较的值)之前添加一个“安全”字符,以确保将该表达式识别为字符串比较:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]