多个逻辑运算符(((A || B)&& C),以及“意外令牌附近的语法错误”


24

我正在使用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

结果是:

line 322: syntax error near unexpected token `[['

然后,我尝试:

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

结果是:

line 322: syntax error near unexpected token `[['

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

如何((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

Answers:


42

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

Shell的要点是运行命令。开括号命令[是执行单个测试¹的命令。您甚至可以将其写为test(没有最后一个括弧)。在||&&运营商壳运营商,他们结合的命令,而不是测试。

所以当你写

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]

解析为

[ [ "$A" -eq "0" ] ||
[ "$B" -ne "0" ] ] &&
[ "$C" -eq "0" ]

这与

test [ "$A" -eq "0" ||
test "$B" -ne "0" ] &&
test "$C" -eq "0"

注意不平衡的括号吗?是的,那不好。您用括号进行的尝试具有相同的问题:假括号。

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

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then 

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

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then 

如果您的所有测试都是数值测试,则还有另一种方法可以界定人工表达。算术表达式使用非常类似于C的语法执行整数计算。

if (((A == 0 || B != 0) && C == 0)); then 

您可能会发现我的bash支架底漆很有用。

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

¹ 它也可以将多个测试与布尔运算符结合在一起,但这使用起来很麻烦并且存在一些隐患,所以我将不作解释。


谢谢吉尔斯。这对Bash 2到Bash 4都适用吗?我需要的东西轻度的便携性,但Kusalananda提到的一些事情我是不会做的是便携式(这是否意味着我做的是不是便携式?)。这里,轻度通过击装置击2 4.

@jww [[ … ]]是在bash 2.02中添加的。((…))是在bash 2.0中添加的。
吉尔斯(Gillles)“所以别再作恶了”

@吉尔斯-谢谢。重击2可能是大多数人可笑的。这是由于我们的治理,并且不愿意放弃旧平台。Bash 2和GCC 3出现在我们的Fedora 1测试中。我们会偶尔使用较旧的平台,但必须有理由。我们不订阅Apple,Microsoft,Mozilla等放弃软件的政策。

@jww请明白的优先级||,并&&从变化[[[((。等于优先[(使用括号来控制计算顺序),但在&&具有更高的优先级[[((||(如在C)。

6

用途[[

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...

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

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

3

使用-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

谢谢。我碰到了-a-o,但没有进行实验。Stack Overflow上有人说要避免这种情况。我大多同意他们的观点,因为脚本使用它们的可读性较差。

...但更便于携带。
库萨兰达

@Kusalananda-感谢有关便携性的注意事项。该脚本必须在具有Bash 2到Bash 4的系统上运行[[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]

只要您坚持使用bash或理解的任何其他外壳,都不会有任何问题[[ ... ]]
库萨兰达
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.