[[ expr1 || 之间的区别 expr2 ]] 和 [[ expr1 ]] || [[expr2]]

roa*_*ima 7 bash

考虑两个条件表达式expr1and expr2,例如$i -eq $jand $k -eq $l。我们可以bash通过多种方式来编写它。这里有两种可能

[[ expr1 || expr2 ]]

[[ expr1 ]] || [[ expr2 ]]
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

A.B*_*A.B 8

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

在大多数语言中,如 C,当一个子句已知为真或假时,不需要根据操作评估剩余部分:如果真不在逻辑之后在它之后,如果假不在逻辑和之后,等等。这当然允许例如在指针为 NULL 时停止,而不是尝试在下一个子句中取消引用它。

但是sh[ expr1 -o expr2 ]构造(包括 bash 的实现)并没有这样做:它总是评估双方,当人们只希望评估expr1 时。这样做可能是为了与test命令实现兼容。另一方面, sh||&&确实遵循通常的原则:如果不会改变结果,则不进行评估。

所以要注意的区别是:

: > /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
Run Code Online (Sandbox Code Playgroud)

产生:

true
or-was-evaluated
Run Code Online (Sandbox Code Playgroud)

上面,每个都[可以替换为/usr/bin/[which 是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
Run Code Online (Sandbox Code Playgroud)

或者

: > /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
Run Code Online (Sandbox Code Playgroud)

只会让步trueeffect留空:||行为正确,并且也[[更正了这个问题。


更新:

正如@StéphaneChazelas 所评论的,我错过了与最初问题相关的几个不同之处。我将把最重要的一项(至少对我而言)放在这里:运营商的优先级。

虽然 shell 不会考虑优先级:

if true || true && false; then
    echo true
else
    echo false
fi
Run Code Online (Sandbox Code Playgroud)

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

false
Run Code Online (Sandbox Code Playgroud)

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

if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
    echo true
else
    echo false
fi
Run Code Online (Sandbox Code Playgroud)

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

true
Run Code Online (Sandbox Code Playgroud)

至少对于kshbashzsh

所以[[ ]]拥有既提高了性能[ ]和直接壳逻辑运算符。