为啥&&和||优先于 -a 和 -o

Posted

技术标签:

【中文标题】为啥&&和||优先于 -a 和 -o【英文标题】:Why are && and || preferred to -a and -o为什么&&和||优先于 -a 和 -o 【发布时间】:2016-04-17 18:41:08 【问题描述】:

在 bash 中编写 if 块时,shellcheck 告诉我 &&|| 优于使用 -a-o

为什么?它更快,或者只是为了让脚本看起来更干净的风格偏好?

我得到的具体信息是:

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

【问题讨论】:

如果 shellcheck 报告了问题,它会在问题旁边打印一个链接到描述。 @hek2mgl 我使用的是本地版本,它只给了我一个问题代码,但我没有找到任何有用的代码来寻找该代码 @MatthewHerbst 检查这个:github.com/koalaman/shellcheck/wiki/SC2166 @hek2mgl 不知道为什么我找不到,谢谢! 【参考方案1】:

来自the POSIX specification for test

4 个参数:

结果未指定。

[OB XSI] [选项开始] 在符合 XSI 的系统上,应使用前面描述的优先级和关联性规则来评估初级和运算符的组合。此外,字符串比较二元基元“=”和“!=”应具有比任何一元基元更高的优先级。 [选项结束]

因此:test 的使用与三个以上的参数 - 如果您使用的是 -a-o,您将依赖它 - 没有未扩展 POSIX 明确指定的行为。


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

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

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

...它既愚蠢又古老,对吧?实际上,!考虑foo=(bar=) 的情况,有人运行如下命令:

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

扩展为以下内容:

if [ ( -a ) ]

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


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

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

...你会这样写:

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

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

【讨论】:

那么,就我对POSIX的基本了解而言,这基本上意味着代码&&||与其他可能没有扩展POSIX的机器更兼容? @MatthewHerbst,这不仅仅是它是否扩展的问题——POSIX 规范本身并没有描述-a-o 需要如何为所有 POSIX 提供足够详细的行为-兼容的实现在模棱两可的情况下表现得完全相同。 请注意[ 的结果会在第一次评估后影响$PIPESTATUS 数组。使用内部的 [[ 就像在 if [[ "$PIPESTATUS[0]" -ne 0 && "$PIPESTATUS[1]" -ne 0 ]]; then... 中一样,至少对于 Bash。

以上是关于为啥&&和||优先于 -a 和 -o的主要内容,如果未能解决你的问题,请参考以下文章

Servlet 过滤器(自动登录)优先于声明性安全检查

为啥正文中的 javascript 函数优先于头部中的函数?

在 Python 中,为啥属性优先于实例属性?

为啥使用比使用更好?

for循环 && for-each

给轴和刻度线标记优先于绘制线