bash/shell 数字上下文中的递归变量扩展从何而来?
Where does the recursive variable expansion in bash/shell numeric contexts come from?
POSIX 规范说明 Arithmetic Expansion
[i]f the shell variable x contains a value that forms a valid integer constant, optionally including a leading plus or minus sign, then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value.
这是一个合理的快捷方式,可以很好地清理复杂的表达式。
bash(来自 CentOS 5 的版本 3.2.25(1)-release
和来自 debian unstable 的 4.3.33(1)-release
)以及 ksh(来自 CentOS 5 的Version AJM 93t+ 2010-06-21
)似乎都迈出了一步然而,远不止于此。
它们似乎都以递归方式扩展算术扩展中遇到的变量(以及 [[
中使用数字运算符产生的数字上下文)。
具体来说:
$ set -x
$ bar=5
+ bar=5
$ foo=bar
+ foo=bar
$ [ foo -gt 4 ]; echo $?
+ '[' foo -gt 4 ']'
-bash: [: foo: integer expression expected
+ echo 2
2
$ [[ foo -gt 4 ]]; echo $?
+ [[ foo -gt 4 ]]
+ echo 0
0
$ [[ foo -eq 0 ]]; echo $?
+ [[ foo -eq 0 ]]
+ echo 1
1
$ [[ foo -eq 5 ]]; echo $?
+ [[ foo -eq 5 ]]
+ echo 0
0
$ (( foo == bar )); echo $?
+ (( foo == bar ))
+ echo 0
0
$ (( foo == 1 )); echo $?
+ (( foo == 1 ))
+ echo 1
1
这种行为从何而来,为什么会令人向往?
它使得使用 [[
代替 [
显式 less 在与数字运算符一起使用时是安全的,因为无效值和印刷错误来自脚本错误到默默有效(但可能是错误的)测试。
编辑:作为附带问题,如果有人碰巧知道 什么时候 这个 "feature" 被添加到 bash/etc。我也有兴趣知道。
比你想象的还要糟糕。变量的值被递归地当作一个算术表达式:
$ foo='bar+bar'
$ echo $((foo))
10
Shell Arithmetic 上的 bash 手册部分说:
The value of a variable is evaluated as an arithmetic expression when it is referenced, or when a variable which has been given the integer attribute using ‘declare -i’ is assigned a value.
后半部分意味着你可以做:
$ declare -i int
$ int=bar+bar
$ echo $int
10
请注意,none 这违反了您在上面引用的规范。它只说明如果变量的值是整数常量应该做什么。它没有说明如果值是其他值应该做什么,这使得实现可以添加这样的扩展。 Bash Hackers Wiki 解释:
If the variable doesn't hold a value that looks like a valid expression (numbers or operations), the expression is re-used to reference, for example, the named parameters
如果最终的展开不是一个有效的表达式,你会得到一个错误:
$ foo='a b'
$ bar=foo
echo $((bar))
bash: a b: syntax error in expression (error token is "b")
所以如果你的变量包含随机的东西,它很可能会导致错误。但是,如果它只包含一个单词,这是有效的变量语法,那么如果未设置变量,它将计算为 0
。
POSIX 规范说明 Arithmetic Expansion
[i]f the shell variable x contains a value that forms a valid integer constant, optionally including a leading plus or minus sign, then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value.
这是一个合理的快捷方式,可以很好地清理复杂的表达式。
bash(来自 CentOS 5 的版本 3.2.25(1)-release
和来自 debian unstable 的 4.3.33(1)-release
)以及 ksh(来自 CentOS 5 的Version AJM 93t+ 2010-06-21
)似乎都迈出了一步然而,远不止于此。
它们似乎都以递归方式扩展算术扩展中遇到的变量(以及 [[
中使用数字运算符产生的数字上下文)。
具体来说:
$ set -x
$ bar=5
+ bar=5
$ foo=bar
+ foo=bar
$ [ foo -gt 4 ]; echo $?
+ '[' foo -gt 4 ']'
-bash: [: foo: integer expression expected
+ echo 2
2
$ [[ foo -gt 4 ]]; echo $?
+ [[ foo -gt 4 ]]
+ echo 0
0
$ [[ foo -eq 0 ]]; echo $?
+ [[ foo -eq 0 ]]
+ echo 1
1
$ [[ foo -eq 5 ]]; echo $?
+ [[ foo -eq 5 ]]
+ echo 0
0
$ (( foo == bar )); echo $?
+ (( foo == bar ))
+ echo 0
0
$ (( foo == 1 )); echo $?
+ (( foo == 1 ))
+ echo 1
1
这种行为从何而来,为什么会令人向往?
它使得使用 [[
代替 [
显式 less 在与数字运算符一起使用时是安全的,因为无效值和印刷错误来自脚本错误到默默有效(但可能是错误的)测试。
编辑:作为附带问题,如果有人碰巧知道 什么时候 这个 "feature" 被添加到 bash/etc。我也有兴趣知道。
比你想象的还要糟糕。变量的值被递归地当作一个算术表达式:
$ foo='bar+bar'
$ echo $((foo))
10
Shell Arithmetic 上的 bash 手册部分说:
The value of a variable is evaluated as an arithmetic expression when it is referenced, or when a variable which has been given the integer attribute using ‘declare -i’ is assigned a value.
后半部分意味着你可以做:
$ declare -i int
$ int=bar+bar
$ echo $int
10
请注意,none 这违反了您在上面引用的规范。它只说明如果变量的值是整数常量应该做什么。它没有说明如果值是其他值应该做什么,这使得实现可以添加这样的扩展。 Bash Hackers Wiki 解释:
If the variable doesn't hold a value that looks like a valid expression (numbers or operations), the expression is re-used to reference, for example, the named parameters
如果最终的展开不是一个有效的表达式,你会得到一个错误:
$ foo='a b'
$ bar=foo
echo $((bar))
bash: a b: syntax error in expression (error token is "b")
所以如果你的变量包含随机的东西,它很可能会导致错误。但是,如果它只包含一个单词,这是有效的变量语法,那么如果未设置变量,它将计算为 0
。