考虑两个条件表达式expr1
and expr2
,例如$i -eq $j
and $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 ]]
。
我认为您看到的建议是针对 POSIX sh和/或
test
兼作命令的[
命令,而不是[[
出现在 ksh 中的构造(感谢 Stéphane Chazelas 的提示)并且也用于例如 bash、zsh 和其他一些贝壳。在大多数语言中,如 C 语言,当一个子句已知为真或假时,无需根据操作评估其余部分:如果为真,则不在逻辑之后或之后,如果为假,不在逻辑and之后,等等。这当然允许例如在指针为 NULL 时停止,而不是尝试在下一个子句中取消引用它。
但是sh的
[ expr1 -o expr2 ]
构造(包括 bash 的实现)并没有这样做:它总是评估双方,而人们只想评估expr1。这样做可能是为了与test
命令实现兼容。另一方面,sh||
和&&
do 遵循通常的原则:如果它不会改变结果,则不进行评估。所以要注意的区别是:
产生:
上面,每个
[
都可以替换为命令/usr/bin/[
的别名,之前使用的是内置到 shell 中的。test
[
而接下来的两个构造:
或者
只会让出
true
并effect
留空:||
行为正确,并且也[[
纠正了这个问题。更新:
正如@StéphaneChazelas 评论的那样,我错过了与最初问题相关的几个差异。我将在这里提出最重要的一项(至少对我而言):操作员的优先级。
虽然外壳不会考虑优先级:
产量(因为没有优先级,因此首先
true || true
评估,然后&& false
):[[ ]]
运算符内部&&
优先于||
:产量(因为
1 -eq 1 && 1 -eq 0
被分组,因此是 的第二个成员||
):至少对于ksh,bash,zsh。
因此
[[ ]]
,改进了[ ]
直接 shell 逻辑运算符的行为。