shell中这个数值计算错误80%的人都遇到过

355 阅读2分钟

image.png 当从文件或命令中读取数字,然后对其进行算术运算时,前导零可能会造成问题:

$ echo $((09))
bash: 09: value too great for base (error token is "09")

当使用带有零填充的值进行数学运算时,该值被视为八进制(基数为8)。在最好的情况下,你会收到错误消息,因为8和9是无效的八进制数字。在最糟糕的情况下,你可能不会立即注意到问题,但程序将在后续失败。

这个问题经常发生在读取时间和日期组成部分时,因为它们通常以两位数的形式进行零填充(例如作为时间的08:11:42,或者作为日期的2013-09-14)。

解决此问题有两个简单的方法:要么去除前导零,要么强制bash将值视为十进制(基数为10)。在算术表达式页面上提供了示例、解释和一些额外的警告。

此外,还值得指出的是,当从外部源读取值并尝试进行算术运算时,不需要余八进制或十六进制解释的问题是您可能遇到的唯一问题。恶意用户还可以通过特殊设计的值引发任意代码执行。

$ a=42 b='x[$(date >&2)0]'
$ echo $((a + b))
Thu Apr 29 22:37:22 EDT 2021
42

重要的是,在来自不受信任的源的数字上执行基本的输入验证。确保在使用之前它们确实是数字。像 date(1) 命令使用 +%m 或 +%H 这样的选项从可信源获取的值是安全的,因此你只需要担心这些情况下的前导零。

备注:在 Bash 5.1 版本中修复了这个问题。在 Bash 5.1 及以后的版本中,数字前面带上 0 会被解析为十进制数字,不再被解析为八进制数字。例如,077 会被解析为十进制的 77。因此使用shell编程的时候务必注意自己的shell版本。