我试图了解逻辑运算符优先级在 bash 中是如何工作的。例如,我会期望以下命令不会回显任何内容。
true || echo aaa && echo bbb
Run Code Online (Sandbox Code Playgroud)
然而,出乎我的意料,bbb被打印出来了。
有人可以解释一下,我如何理解bash 中的复合&&和||运算符?
Jos*_* R. 168
在许多计算机语言中,具有相同优先级的运算符是左结合的。也就是说,在没有分组结构的情况下,最左边的操作首先执行。Bash也不例外。
这是重要的,因为,在击,&&并且||具有相同的优先级。
所以在你的例子中发生的是最左边的操作 ( ||) 首先执行:
true || echo aaa
Run Code Online (Sandbox Code Playgroud)
由于true显然是正确的,因此||运算符短路并且整个语句都被认为是正确的,而无需echo aaa像您期望的那样进行评估。现在要做最右边的操作:
(...) && echo bbb
Run Code Online (Sandbox Code Playgroud)
由于第一个操作评估为真(即退出状态为 0),就好像您正在执行
true && echo bbb
Run Code Online (Sandbox Code Playgroud)
所以&&不会短路,这就是为什么你看到bbb回声。
你会得到相同的行为
false && echo aaa || echo bbb
Run Code Online (Sandbox Code Playgroud)
基于评论的注释
[[...]]or 之类的关键字结合使用时,情况就不是这样了,((...))或者使用-oand-a运算符作为testor[命令的参数。在这种情况下,AND(&&或-a)优先于 OR(||或-o)。感谢 Stephane Chazelas 的评论澄清了这一点。似乎在 C和类 C 语言&&中的优先级高于||这可能是您期望原始构造表现得像的原因
true || (echo aaa && echo bbb).
Run Code Online (Sandbox Code Playgroud)
然而,这不是 Bash 的情况,其中两个运算符具有相同的优先级,这就是 Bash 使用左结合规则解析表达式的原因。感谢凯文提出这个问题的评论。
也可能存在评估所有 3 个表达式的情况。如果第一个命令返回非零退出状态,||则不会短路并继续执行第二个命令。如果第二个命令以零退出状态返回,则&&不会短路并且将执行第三个命令。感谢 Ignacio Vazquez-Abrams 提出的评论。
Oli*_*Oli 86
如果您希望多项事情取决于您的情况,请将它们分组:
true || { echo aaa && echo bbb; }
Run Code Online (Sandbox Code Playgroud)
那什么都不打印,而
true && { echo aaa && echo bbb; }
Run Code Online (Sandbox Code Playgroud)
打印两个字符串。
发生这种情况的原因比约瑟夫想象的要简单得多。记住 Bash 用||和做什么&&。这都是关于上一个命令的返回状态。查看原始命令的字面意思是:
( true || echo aaa ) && echo bbb
Run Code Online (Sandbox Code Playgroud)
第一个命令 ( 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
Run Code Online (Sandbox Code Playgroud)
Doc*_*ger 22
在&&和||运营商都没有确切的内嵌替代IF-THEN-ELSE。尽管如果小心使用,它们可以完成很多相同的事情。
一个单一的测试是直接和明确的......
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
Run Code Online (Sandbox Code Playgroud)
但是,尝试添加多个测试可能会产生意想不到的结果......
[[ 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?)
Run Code Online (Sandbox Code Playgroud)
为什么 FALSE和TRUE 都会回显?
这里发生的事情是我们没有意识到&&并且||是重载的运算符,它们在条件测试括号内的行为与[[ ]]我们这里的 AND 和 OR(条件执行)列表中的行为不同。
从 bash 联机帮助页(已编辑)...
列表
列表是由运算符 ;、&、&& 或 ?? 之一分隔的一个或多个管道的序列,并且可选地以 ;、& 或 之一终止。在这些列表运算符中,&& 和 ?? 具有相同的优先级,其次是 ; 和 & 具有相同的优先级。
一个或多个换行符的序列可能会出现在列表中,而不是用分号来分隔命令。
如果命令由控制运算符 & 终止,shell 将在子 shell 的后台执行该命令。shell 不等待命令完成,返回状态为 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"
Run Code Online (Sandbox Code Playgroud)
好的。如果这是正确的,那么为什么最后一个示例会回显任何内容?
[[ 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"
Run Code Online (Sandbox Code Playgroud)
使用多个命令&&或||在命令列表中使用时出现逻辑错误的风险非常高。
建议
单个&&或||在命令列表中按预期工作,因此非常安全。如果是不需要 else 子句的情况,则可以更清楚地遵循以下内容(需要花括号将最后 2 个命令分组)...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
Run Code Online (Sandbox Code Playgroud)
Multiple &&and||操作符,除了最后一个操作符之外的每个命令都是一个测试(即在括号内[[ ]]),通常也是安全的,但最后一个操作符的行为与预期一致。最后一个运算符的作用更像是一个thenorelse子句。
| 归档时间: |
|
| 查看次数: |
105100 次 |
| 最近记录: |