[[ expr1 || 之间的区别expr2 ]] 和 [[ expr1 ]] || [[表达式2]]

[[ expr1 || 之间的区别expr2 ]] 和 [[ expr1 ]] || [[表达式2]]

考虑两个条件表达式expr1expr2,例如$i -eq $j$k -eq $l。我们可以用bash多种方式来写这个。这里有两种可能性

[[ expr1 || expr2 ]]

[[ expr1 ]] || [[ expr2 ]]

我相当确定我在这里看到了应该首选第二个的建议,但我找不到支持这一点的证据。

这是一个示例脚本,似乎证明没有区别:

for i in 0 1
do
  for j in 0 1
  do
    for k in 0 1
    do
      for l in 0 1
      do
        if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yes\t"; else printf "1-no\t"; fi
        if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yes\n"; else printf "2-no\n"; fi
      done
    done
  done
done

输出显示两个条件构造产生相同的结果:

1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-no    2-no
1-no    2-no
1-yes   2-yes
1-yes   2-yes
1-no    2-no
1-no    2-no
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes

使用一种结构比使用另一种结构有什么好处吗?

对于奖励积分,相同的问题,但使用||和概括为多个条件&&。例如,[[ expr1 && expr2 || expr3 ]]

答案1

我认为您看到的建议是针对 POSIX 的和/或test兼作[命令的命令,而不是[[ksh 中出现的结构(感谢 Stéphane Chazelas 的提示),并且也用于 bash、zsh 和其他一些 shell 中。

在大多数语言(如 C)中,当已知子句为 true 或 false 时,无需根据操作来计算剩余部分:if true 不在逻辑之后或者跟随它,如果为 false 则不在逻辑之后等等。这当然允许例如在指针为 NULL 时停止,而不是尝试在下一个子句中取消引用它。

[ expr1 -o expr2 ]构造(包括 bash 的实现)不会这样做:它总是评估双方,而当一方只想表达式1待评估。这样做可能是为了与test命令实现兼容。另一方面,sh||&&do 遵循通常的原则:如果不会改变结果,则不进行评估。

所以需要注意的区别是:

: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
    echo true;
fi
cat /tmp/effect

产生:

true
or-was-evaluated

上面的每个命令[都可以替换为命令/usr/bin/[的别名test,之前使用过[它内置到 shell 中。

接下来的两个构造:

: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
    echo true;
fi
cat /tmp/effect

或者

: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
    echo true;
fi
cat /tmp/effect

只会产生true并留空effect||行为正确,并且[[也纠正了这个问题。


更新:

正如@StéphaneChazelas 评论的那样,我错过了与最初问题相关的几个差异。我将在这里提出最重要的一个(至少对我来说):操作员的优先级。

虽然 shell 不会考虑优先级:

if true || true && false; then
    echo true
else
    echo false
fi

产生(因为没有优先级,因此首先true || true评估,然后&& false):

false

[[ ]]运算符内部&&优先于||:

if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
    echo true
else
    echo false
fi

产量(因为1 -eq 1 && 1 -eq 0已分组,因此是 的第二个成员||):

true

至少对于,巴什,桀骜

因此,与直接 shell 逻辑运算符[[ ]]相比,行为得到了改进。[ ]

相关内容