双括号结构在 bash 中如何工作?

How does the double parenthesis construct work in bash?

我读到 here 双括号允许 C 风格的变量操作。但是,当我尝试比较字符串时,它没有按预期工作:

(( "a" == "b" )) && echo yes || echo no
# shows yes

我也对 this 如何将变量用作布尔值感到困惑。按照链接答案中的示例,我尝试了以下操作:

true=1
false=0
a=true
(( a )) && echo yes || echo no
# shows yes
a=false
(( a )) && echo yes || echo no
# shows no

但是 a 不是 true 或 false 的字符串值吗?

此外,由于在 bash 中“无错误”值 (0) 被视为真而任何“错误”值(非零)被视为假,为什么它看起来像这里采用相反的约定?

要注意的主要事情是 double-parenthesis 构造允许 算术计算和扩展 ,而不是内联 C 解释器。因此,只有Shell Arithmetic中定义的规则适用,也就是说,只有整数类型的C运算在双括号中起作用。


第一个例子:bash构造先展开

首先根据 bash 规则扩展算术运算符之外的任何内容,例如quotes, parameter expansion、bash range {1..5} 和 list{a,b} 构造,在双括号计算开始之前。

在第一个例子中,双引号导致里面的内容被解释为一个单词(在 double-paren 中没有影响)并且还计算以 $ 开头的东西(但是引号中有 none ), 所以第一个例子简单地变成 (( a == b )).

因此,了解 (( )) 工作原理的最佳方法是首先在脑海中计算出所有 bash 结构,然后将其插入。您还可以编写示例来测试您的假设.

发生参数扩展的示例:

a=1
b=2
(( a = $b )) # becomes (( a = 2 ))
(( a = b )) # straight arithmetic evaluation of a = b within the double parenthesis
# they produce the same result but how they arrive at the result is different
(( $a = b )) # becomes (( 2 = b ))
# syntax error as that's not a valid expression.

备注

当您比较密切相关的 $(( ))(( )) 结构时,有一些特殊之处。前者 (Arithmetic Expansion) 将表达式视为表达式在双引号内,而后者则不然,如上所述。


例子二:右值位置的变量递归展开

Shell Arithmetic中有一些微妙的规则:

  1. “变量的值在被引用时作为算术表达式求值”
  2. “或者当使用declare -i赋予整数属性的变量被赋值时”。
  3. “在不使用参数扩展语法的情况下按名称引用时,为 null 或未设置的 shell 变量的计算结果为 0”

稍微尝试一下后,您会发现这基本上意味着右值中的任何变量都将被递归计算,直到它达到一个整数值,或者是一个 undefined/null 变量姓名:

b=c
c=d
(( a = b ))
echo $a 
# gives 0
d=3
(( a = b ))
echo $a
# gives 3

unset d
declare -i a
a=b
echo $a
# gives 0
d=3
a=b
echo $a
# gives 3

您还可以玩把戏,将表达式放入变量中,然后再对其求值:

b=2
c=3
d=c
e=b+d
(( a = e ))
echo $a
# gives 5, as it unfolds like a=b+d; a=2+c; a=2+3

因此在问题的示例中,a 评估为 true,然后评估为 1 以给出最终结果。


(( ))如何颠倒真假的解释

(( 0 ))
echo $? # print the return code of the previous call
# prints 1, which indicates error/false in shell

(( 1 ))
echo $?
# prints 0, indicating success/true

(( 2 ))
echo $?
# prints 0

(( -1 ))
echo $?
# prints 0

所以括号内的行为与C对true和false的解释是一致的,0表示false,non-zero表示true。 (( )) 将 false“转换”为 return 值 1,将 true 转换为 return 值 0。