bash - bash/shell 数字上下文中的递归变量扩展从何而来?

标签 bash shell posix ksh arithmetic-expressions

关于 Arithmetic Expansion 的 POSIX 规范说明那个

[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(版本 3.2.25(1)-release 来自 CentOS 5 和 4.3.33(1)-release 来自 debian unstable)以及 ksh(版本 AJM 93t+ 2010-06-21 来自 CentOS 5) 然而似乎都比那更进一步。

它们似乎都递归地扩展在算术扩展中遇到的变量(以及 [[ 中使用数字运算符产生的数字上下文)。

具体来说:

$ 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

这种行为从何而来,为什么会令人满意?

当与数字运算符一起使用时,它使得使用 [[ 代替 [ 显式不太安全,因为无效值和打印错误从脚本错误到静默有效(但可能是错误的)测试。

编辑:作为附带问题,是否有人碰巧知道何时此“功能”被添加到 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

请注意,所有这些都不违反您在上面引用的规范。它只说明如果变量的值是整数常量应该做什么。它没有说明如果值是其他值应该做什么,这使得实现可以添加这样的扩展。 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

关于bash - bash/shell 数字上下文中的递归变量扩展从何而来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29980940/

相关文章:

php - 字符串加密/解密

linux - Bash 检查用户是否存在,如果存在则在用户名中添加数字

bash - 我如何对 ksh93 进行编程以使用 bash 自动完成功能?

linux - 计算日志中最前面的重复行

bash - 如果文件存在于给定路径中则显示文件

c - 如何从 NSURL 获取结构文件?

c - 当非阻塞流套接字连接时调用 getsockname() 是否安全?

linux - cronjob 没有按预期工作

php - 使用 utf-8 文本输入通过 shell_exec 调用程序

c - 向进程中的所有线程发送信号