为什么 && 和 ||优于 -a 和 -o

Why are && and || preferred to -a and -o

在 bash 中写入 if 块时,shellcheck 告诉我 &&|| 比使用 -a-o.

为什么?它更快,或者只是一种让脚本看起来更简洁的风格偏好?

我得到的具体信息是:

^-- SC2166: Prefer [ p ] || [ q ] as [ p -o q ] is not well defined.

来自 the POSIX specification for test:

  • 4 arguments:

    The results are unspecified.

    [OB XSI] [Option Start] On XSI-conformant systems, combinations of primaries and operators shall be evaluated using the precedence and associativity rules described previously. In addition, the string comparison binary primaries '=' and "!=" shall have a higher precedence than any unary primary. [Option End]

因此:使用带有三个以上参数的 test —— 如果你使用 -a-o,你依赖于它 —— 没有行为由未扩展 POSIX.

明确指定

现在,为什么会这样?因为在某些情况下,解析器可能会根据变量值做错事。

你还记得有人建议你做这样的事情吗?

if [ "x$foo" = "x$bar" ]; then ...

...这很愚蠢很古老,对吧?实际上,没有!考虑 foo=(bar=) 的情况,有人运行这样的命令:

if [ "$foo" -a "$bar" ]

扩展为以下内容:

if [ ( -a ) ]

...我们如何解析它?嗯,它 可以 是一个分组运算符(是的,test 在历史上被指定支持它们),检查 -a 是否是 non-null;或者它可以检查 () 本身是否都是 non-empty 字符串;这是模棱两可的。这种歧义是 -a-o 不再是首选语法的原因。


那么,替代品是什么样子的?而不是:

[ "$foo" -gt "$bar" -a "$foo" -lt "$qux" ]

...你会这样写:

[ "$foo" -gt "$bar" ] && [ "$foo" -lt "$qux" ]

...关闭两个测试表达式并使用 shell 语法组合它们的输出。由于 [ / test 是一个 shell 内建函数,它不需要作为外部命令执行,所以它没有像以前那样的性能开销70 年代 运行 test 意味着调用 /usr/bin/test.