带引号的 Shell 算术展开

带引号的 Shell 算术展开

在 Bash 和 Dash 中,在算术扩展中使用引号是非法的:

$ bash -c 'x=123;echo $(("$x"))'
bash: "123": syntax error: operand expected (error token is ""123"")
$ dash -c 'x=123;echo $(("$x"))'
dash: 1: arithmetic expression: expecting primary: ""123""

当作为 sh 调用时,Bash 会给出相同的错误。不过 Ksh 和 FreeBSD 的 Bourne Shell 并不介意:

$ ksh -c 'x=123;echo $(("$x"))'
123
$ sh -c 'x=123;echo $(("$x"))'
123

根据Bash 参考手册:

该表达式被视为位于双引号内,但括号内的双引号不会被特殊处理。所有代币......都会经历......报价删除。

(本质上与POSIX说。)

最后,与其他算术上下文(例如条件表达式)$(( ))相比,Bash 的处理方式有所不同。(( ))后者带有引号就可以了。

要么我不明白什么报价删除意味着此处,或者这是其中一些 shell 实现中的错误。如果是前者,“删除引号”到底意味着什么?或者,这只是一个错误?

答案1

我很困惑这是一个糟糕的实现还是糟糕的文档。 Bash 对于引用删除是这样说的:

报价删除

在前面的扩展之后,所有未加引号的字符 \'、 和"不是由上述扩展之一产生的都将被删除。

我认为关键可能是“所有未引用的该段落中的所有内容$(( ))都被视为用双引号括起来。如果这些字符位于括号内,则它们都会被引用,从而使引号删除本质上是一个空操作。例如,请注意其他“删除”的方式" 处理字符(另请注意如何保留尾随空格,因为如何解析带引号的字符串):

$ echo $(( '5' ))
bash: '5' : syntax error: operand expected (error token is "'5' ")
$ echo $(( \ ))
bash: \ : syntax error: operand expected (error token is "\ ")

浏览源代码,引号确实需要平衡,因为代码会扫描以确定是$(( ))数学还是嵌套的遗留子表达式。当字符串被识别为算术表达式时,它会被解析为双引号 - 这意味着全部在删除引号之前,内部的字符被视为被引用。

就我个人而言,这就是我更喜欢 ksh 的部分原因 - 特别是对于数学。例如,它将上面的单引号 5 视为 C 字符串,其计算结果为 53。 man ascii看看为什么这是有道理的。 :)

相关内容