多个逻辑运算符 ((A || B) && C) 和“意外标记附近的语法错误”

41 bash shell-script

我正在使用 Bash 3,并且正在尝试形成一个条件。在 C/C++ 中,它非常简单:((A || B) && C). 在 Bash 中,结果并非如此(我认为 Git 作者在转向其他工作之前一定已经贡献了这段代码)。

这不起作用。请注意,这<0 or 1>不是字符串文字;它表示 0 或 1(通常来自grep -i)。

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi
Run Code Online (Sandbox Code Playgroud)

结果是:

line 322: syntax error near unexpected token `[['
Run Code Online (Sandbox Code Playgroud)

然后我尝试:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi
Run Code Online (Sandbox Code Playgroud)

结果是:

line 322: syntax error near unexpected token `[['
Run Code Online (Sandbox Code Playgroud)

部分问题是搜索结果是简单的例子,而不是带有复合条件的更复杂的例子。

如何((A || B) && C)在 Bash 中执行简单的操作?


我准备展开它并在多个块中重复相同的命令:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>

if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then
    ...
elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then
    ... 
fi
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 70

bash 的语法并不像 C 语言,即使它的一小部分受到 C 的启发。您不能简单地尝试编写 C 代码并期望它能够工作。

shell 的主要功能是运行命令。open-bracket 命令[是一个执行单个测试的命令¹。你甚至可以把它写成test(没有最后的右括号)。在||&&运营商壳运营商,他们结合的命令,而不是测试。

所以当你写

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]
Run Code Online (Sandbox Code Playgroud)

这被解析为

[ [ "$A" -eq "0" ] ||
[ "$B" -ne "0" ] ] &&
[ "$C" -eq "0" ]
Run Code Online (Sandbox Code Playgroud)

这与

test [ "$A" -eq "0" ||
test "$B" -ne "0" ] &&
test "$C" -eq "0"
Run Code Online (Sandbox Code Playgroud)

注意到不平衡的括号了吗?是的,那不好。您使用括号的尝试具有相同的问题:伪括号。

将命令组合在一起的语法是大括号。解析大括号的方式需要在它们之前有一个完整的命令,因此您需要使用换行符或分号来终止大括号内的命令。

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then …
Run Code Online (Sandbox Code Playgroud)

还有一种替代方法是使用双括号。与单括号不同,双括号是特殊的 shell 语法。它们分隔条件表达式。在双括号内,您可以使用括号和运算符,如&&and ||。由于双括号是 shell 语法,shell 知道当这些运算符位于括号内时,它们是条件表达式语法的一部分,而不是普通 shell 命令语法的一部分。

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then …
Run Code Online (Sandbox Code Playgroud)

如果您的所有测试都是数字的,那么还有另一种方法来界定算术表达式。算术表达式使用非常类似于 C 的语法执行整数计算。

if (((A == 0 || B != 0) && C == 0)); then …
Run Code Online (Sandbox Code Playgroud)

您可能会发现我的 bash 支架入门很有用。

[可以在普通 sh 中使用。[[并且((特定于 bash(以及 ksh 和 zsh)。

¹它还可以将多个测试与布尔运算符结合起来,但是这使用起来很麻烦并且有一些微妙的陷阱,所以我不会解释它。


Ste*_*itt 11

使用[[

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...
Run Code Online (Sandbox Code Playgroud)

如果您愿意[,可以使用以下方法:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...
Run Code Online (Sandbox Code Playgroud)


Zac*_*ady 5

使用-o运算符而不是嵌套的 ||。-a如果需要,您还可以在其他语句中使用&& 来替换。

   EXPRESSION1 -a EXPRESSION2
          both EXPRESSION1 and EXPRESSION2 are true

   EXPRESSION1 -o EXPRESSION2
          either EXPRESSION1 or EXPRESSION2 is true


if [  "$A" -eq "0" -o "$B" -ne "0"  ] && [ "$C" -eq "0" ]; then echo success;fi
Run Code Online (Sandbox Code Playgroud)

  • 使用 -a 的缺点是,如果第一个表达式为假,它不会短路。因此,如果您依靠短路来防止潜在的致命第二个表达式运行,那么您不能使用 -a。示例:https://pastebin.com/zM77TXW1 (2认同)