Answers:
在许多计算机语言中,具有相同优先级的运算符是左关联的。即,在没有分组结构的情况下,最左边的操作首先被执行。Bash 也不例外。
因为,在击,这一点很重要&&
,并||
具有相同的优先级。
因此,在您的示例中发生的是最左边的操作(||
)首先执行:
true || echo aaa
由于true
显然是正确的,所以||
操作员会短路,整个语句被认为是正确的,而无需echo aaa
按您期望的那样进行评估。现在剩下要做最右边的操作了:
(...) && echo bbb
由于第一个操作的评估结果为true(即退出状态为0),就好像您正在执行
true && echo bbb
因此&&
不会短路,这就是您看到bbb
回声的原因。
您将获得与相同的行为
false && echo aaa || echo bbb
基于注释的注释
[[...]]
or ((...))
或关键字一起使用,或将-o
and -a
运算符用作test
or [
命令的参数时,情况并非如此。在这种情况下,AND(&&
或-a
)优先于OR(||
或-o
)。感谢Stephane Chazelas的评论澄清了这一点。似乎在C和类似C的语言中,&&
其优先级高于||
,这可能就是为什么您希望原始构造的行为像
true || (echo aaa && echo bbb).
但是Bash情况并非如此,因为这两个运算符的优先级都相同,这就是Bash使用左关联规则解析您的表达式的原因。感谢Kevin提出的评论。
在某些情况下,可能会同时评估所有3个表达式。如果第一个命令返回非零退出状态,||
则不会短路,然后继续执行第二个命令。如果第二个命令返回的退出状态为零,则&&
不会短路,第三个命令将被执行。感谢Ignacio Vazquez-Abrams提出的评论。
&&
优先级高于||
,因此将发生OP的预期行为。习惯这种语言的粗心用户可能不会意识到在bash中它们具有相同的优先级,因此可能需要更明确地指出他们在bash中具有相同的优先级。
如果您希望多种情况取决于您的状况,请将它们分组:
true || { echo aaa && echo bbb; }
那什么也没打印
true && { echo aaa && echo bbb; }
打印两个字符串。
发生这种情况的原因要比约瑟夫所说的简单得多。记住Bash对||
和的作用&&
。全部与上一条命令的返回状态有关。查看原始命令的字面方式是:
( true || echo aaa ) && echo bbb
第一个命令(true || echo aaa
)将以退出0
。
$ true || echo aaa; echo $?
0
$ true && echo aaa; echo $?
aaa
0
$ false && echo aaa; echo $?
1
$ false || echo aaa; echo $?
aaa
0
(true || echo aaa) && echo bbb
正是我要写的。
;
。没有这个,它将无法工作!
echo bbb;
,在第一个示例中)。一旦我发现自己想不到的话,这个答案正是我想要的。+1帮助我弄清楚如何实现自己想要的目标!
在&&
和||
运营商都没有精确的内联替代IF-THEN-ELSE。尽管使用得当,它们可以完成很多相同的事情。
单个测试是简单明了的...
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
但是,尝试添加多个测试可能会产生意外的结果...
[[ A == A ]] && echo TRUE || echo FALSE # TRUE (as expected)
[[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
[[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
[[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)
为什么同时显示FALSE 和 TRUE?
这里发生的事情是我们尚未意识到,&&
并且||
它们是重载运算符,它们在条件测试括号内的行为与[[ ]]
此处的AND和OR(条件执行)列表中的行为不同。
从bash手册页(已编辑)...
清单
列表是由一个或多个管线组成的序列,这些管线由运算符;,&,&&或││分隔,并可选地由;,&,或之一终止。在这些列表运算符中,&&和││具有相同的优先级,其后是;;和&,具有相同的优先级。
列表中可能会出现一个或多个换行符序列,而不是用分号分隔命令。
如果命令由控制操作符&终止,则外壳程序将在子外壳程序的后台执行该命令。外壳程序不等待命令完成,返回状态为0。按顺序执行;Shell等待每个命令依次终止。返回状态是最后执行的命令的退出状态。
AND和OR列表是分别由&&和││控制运算符分隔的多个管道之一的序列。AND和OR列表以左关联性执行。
AND列表的格式为...
command1 && command2
仅当command1返回退出状态为零时,才执行Command2。OR列表的格式为...
command1 ││ command2
仅当command1返回非零退出状态时才执行Command2。AND和OR列表的返回状态是列表中最后执行的命令的退出状态。
回到我们的最后一个例子...
[[ A == B ]] || echo FALSE && echo TRUE
[[ A == B ]] is false
|| Does NOT mean OR! It means...
'execute next command if last command return code(rc) was false'
echo FALSE The 'echo' command rc is always true
(i.e. it successfully echoed the word "FALSE")
&& Execute next command if last command rc was true
echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"
好的。如果这是正确的,那么为什么倒数第二个示例完全回显任何内容?
[[ A == A ]] || echo FALSE && echo TRUE
[[ A == A ]] is true
|| execute next command if last command rc was false.
echo FALSE Since last rc was true, shouldn't it have stopped before this?
Nope. Instead, it skips the 'echo FALSE', does not even try to
execute it, and continues looking for a `&&` clause.
&& ... which it finds here
echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"
在一个&&
或||
多个命令列表中使用多个逻辑错误的风险很高。
推荐建议
一个&&
或||
一个命令列表可以按预期工作,因此非常安全。如果在不需要else子句的情况下,可以更清楚地遵循以下内容(将大括号括起来以对最后2个命令进行分组)...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
多重运算符&&
和||
运算符(除了最后一个运算符之外的每个命令都是测试)(即,放在方括号内[[ ]]
)通常也很安全,因为除最后一个运算符外,所有命令的行为均符合预期。最后一个运算符的行为更像是then
or else
子句。
我对此也感到困惑,但这是我对Bash读取语句的方式的看法(因为它从左到右读取符号):
true
。到达命令末尾时,将需要对此进行评估。在这一点上,不知道它是否有任何参数。将命令存储在执行缓冲区中。||
。上一条命令现已完成,因此请对其进行评估。命令(缓冲器)中执行:true
。评估结果:0(即成功)。将结果0存储在“上次评估”寄存器中。现在考虑符号||
本身。这取决于上次评估的结果为非零。检查“最后评估”寄存器,发现为0。由于0并非非零,因此不需要评估以下命令。echo
。可以忽略此符号,因为不需要评估以下命令。aaa
。这是命令echo
(3)的参数,但是由于echo
(3)不需要评估,因此可以忽略。&&
。这取决于最后评估的结果为零。检查“最后评估”寄存器,发现为0。由于0为零,因此需要评估以下命令。echo
。一旦到达命令结尾,就需要评估此命令,因为确实需要评估以下命令。将命令存储在执行缓冲区中。bbb
。这是命令echo
(6)的参数。由于echo
确实需要评估,因此添加bbb
到执行缓冲区。echo bbb
。评估结果:0(即成功)。将结果0存储在“上次评估”寄存器中。当然,最后一步会引起bbb
控制台响应。
&&
和||
shell运算符的cmd1 && cmd2 || cmd3
优先级相同,但&&
in((...))
和in的[[...]]
优先级高于||
(((a || b && c))
is((a || (b && c)))
)。这同样适用于-a
/-o
中test
/[
和find
和&
/|
中expr
。