我试图了解逻辑运算符优先级如何在bash中工作。例如,我希望下面的命令不会回显任何内容。

有人可以解释一下,我如何理解bash中bbb&&复合运算符?

#1 楼

在许多计算机语言中,具有相同优先级的运算符是左关联的。也就是说,在没有分组结构的情况下,最先执行最左边的操作。 Bash也不例外。

这很重要,因为在Bash中,&&||具有相同的优先级。

所以,您的示例中发生的是最左边操作(||)首先执行:如您所愿。现在仍然需要执行最右边的操作:

true || echo aaa


由于第一个操作的求值为真(即退出状态为0),就好像您正在执行

(...) && echo bbb


,所以true不会短路,这就是为什么您看到||回波的原因。 />
true && echo bbb


基于注释的注释


您应注意,仅当两个算子具有相同的运算符时,才遵循左关联规则优先。当您将这些运算符与诸如echo aaa&&之类的关键字结合使用,或者将bbb[[...]]运算符用作((...))-o命令的参数时,情况并非如此。在这种情况下,AND(-atest)优先于OR([&&)。感谢Stephane Chazelas的注释澄清了这一点。 >
false && echo aaa || echo bbb


但是,Bash情况并非如此,因为这两个运算符的优先级都相同,这就是Bash使用左关联规则解析表达式的原因。感谢Kevin提出的评论。

在某些情况下,可能会同时评估所有3个表达式。如果第一个命令返回非零退出状态,则-a不会短路,然后继续执行第二个命令。如果第二条命令返回的退出状态为零,则||也不会短路,并且将执行第三条命令。感谢Ignacio Vazquez-Abrams提出的评论。


评论


稍加注释会增加一些混乱:而&&和|| shell运算符,如cmd1 && cmd2 || cmd3的优先级相同,(&()中的&&和[[...]]优先于|| ((((a || b && c))是((a ||(b && c)))))。在test / [中找到-a / -o并查找和&/ |也是如此在expr。

–StéphaneChazelas
13年8月30日在12:17

在类似C的语言中,&&的优先级高于||,因此将发生OP的预期行为。习惯这种语言的粗心用户可能不会意识到在bash中它们具有相同的优先级,因此可能需要更明确地指出他们在bash中具有相同的优先级。

–凯文
2013年8月30日13:06



还要注意,在某些情况下,所有三个命令都可以运行,即中间命令可以返回true或false。

–伊格纳西奥·巴斯克斯(Ignacio Vazquez-Abrams)
13年8月30日在13:42

今天,对我而言,“ bash运算符优先级”在Google上排名最高的是tldp.org/LDP/abs/html/opprecedence.html ...,它声称&&的优先级高于||。但是@JosephR。显然在事实上和法律上都是正确的。 Dash的行为相同,并在pubs.opengroup.org/onlinepubs/009695399/utilities/…中搜索“优先级”,我认为这是POSIX要求,因此我们可以依靠它。我发现的所有错误报告都是作者的电子邮件地址,在过去六年中,该电子邮件地址肯定是垃圾邮件。我还是会尝试...

–马丁·多雷(Martin Dorey)
18年8月21日在19:37

@MartinDorey我以与您相同的方式阅读该页面,但是阅读了以上答案后,我现在将空白行解释为“组分隔符”,以便相邻(非空白)行具有相同的优先级。

–IpsRich
19年8月8日在8:42

#2 楼

如果您要根据自己的情况选择多个物品,请将它们分组: br />打印两个字符串。


发生这种情况的原因比Joseph讲的简单得多。记住Bash对||&&的作用。全部与上一条命令的返回状态有关。查看原始命令的字面方式是:

true || { echo aaa && echo bbb; }


第一个命令(true || echo aaa)与0一起退出。

true && { echo aaa && echo bbb; }


评论


+1用于实现OP的预期结果。请注意,您放置在(true || echo aaa)&& echo bbb中的括号正是我要写的内容。

–约瑟夫·R。
13年8月30日在13:53

很高兴在世界这边看到@Oli。

–脑袋
13年8月30日在16:12

注意半列;在最后。没有这个,它将无法工作!

– Serge Stroobandt
16/12/19在2:46



我遇到了麻烦,因为我在最后一条命令之后缺少尾部分号(例如,在第一个示例中为echo bbb)。一旦我发现自己想不到的话,这个答案正是我想要的。 +1帮助我弄清楚如何实现自己想要的目标!

– Doktor J
17年6月12日在18:03

值得任何对(...)和{...}符号感到困惑的人阅读:命令分组手册

–安塔拉
18年6月4日在14:57

#3 楼

&&||运算符不是if-then-else的精确内联替换。尽管使用得当,它们可以完成很多相同的事情。

单个测试非常简单明了...

尝试添加多个测试可能会产生意外的结果...

[[ A == A ]]  && echo TRUE                          # TRUE
[[ A == B ]]  && echo TRUE                          # 
[[ A == A ]]  || echo FALSE                         # 
[[ A == B ]]  || echo FALSE                         # FALSE


为什么同时返回FALSE和TRUE?我们还没有意识到&&||是重载运算符,它们在条件测试括号[[ ]]中的作用与在此处的AND和OR(条件执行)列表中的作用不同。
已编辑)...


列表

列表是由一个或多个管道组成的序列,这些管道由一个
运算符;,&,分隔&&,或││,并可选地以;,&,
或之一终止。在这些列表运算符中,&&和││具有相同的
优先级,后跟;。

列表中可能会出现一个或多个换行符的序列,而不是用
分号来分隔命令。命令由控制操作符&终止,shell
在子shell中在后台执行命令。 shell不会等待命令完成,返回状态为0。按顺序执行; Shell等待
依次终止每个命令。返回状态是最后执行的命令的退出状态。

AND和OR列表是由&&和││控制运算符分隔的多个管道之一的序列,分别。
用左关联性执行AND和OR列表。

AND列表的格式为... command1 && command2
仅当command1返回退出状态时,才执行Command2。零。

OR列表的格式为... command1 ││ command2
仅当command1返回非零退出状态时才执行Command2。

AND和OR列表的返回状态
是列表中最后执行的命令的退出状态。


回到我们的上一个示例...

[[ 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?)


好的。如果这是正确的,那么为什么倒数第二个示例完全回显任何内容?列表相当高。

建议

命令列表中的单个&&||可以正常工作,因此非常安全。如果在不需要else子句的情况下,可以更清楚地遵循以下内容(将大括号括起来以对最后2条命令进行分组)...

[[ 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"


多个&&||运算符通常安全,因为除了最后一个运算符外,其他所有命令都按预期运行,因此除最后一个指令外的每个命令都是一个测试(即,在方括号&&内)。最后一个运算符的行为更类似于||[[ ]]子句。

#4 楼

我对此也感到困惑,但这是我对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回显到控制台。