考虑两个条件表达式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 ]]。
我认为您看到的建议是针对 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)
只会让步true并effect留空:||行为正确,并且也[[更正了这个问题。
更新:
正如@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)
至少对于ksh,bash,zsh。
所以[[ ]]拥有既提高了性能[ ]和直接壳逻辑运算符。