数值太大不可为算数进制的基
- new,2022-08-19,chenxizhan1995@163.com
缘起
写了个脚本,每个小时执行一次,有一段逻辑要在当前时间为 21:00 ~ 21:59 时才执行。
if (($(date +%H) == 21)); then
echo 晚上 21 点,发送通知
send mail/ok.txt
else
echo 时间不到,不发送通知
fi
晚上写好,第二天早上看日志,八点执行的时候有一段报错
./main.sh:行25: ((: 08: 数值太大不可为算数进制的基 (错误符号是 "08")
把 if (($(date +%H) == 21)); 改成 if ((10#$(date +%H) == 21)); 就好了。
if ((10#$(date +%H) == 21)); then
echo 晚上 21 点,发送通知
send mail/ok.txt
else
echo 时间不到,不发送通知
fi
原理
bash 支持简单的数学计算,叫做 ARITHMETIC EVALUATION。在 $((expr))和 if ((expr))
中的表达式 expr 都遵循 ARITHMETIC EVALUATION 的规则。
bash 手册页 ARITHMETIC EVALUATION 章节对数值字面值有相关描述。
以 0 开头的字面值会按照八进制数字解析,所以 08 报错。同时允许手动指定字面值的进制。
$ echo $((1+2))
3
$ echo $((010))
8
$ echo $((10))
10
$ echo $((0x10))
16
$ echo $((018))
bash: 018: value too great for base (error token is "018")
# 手动指定为 10 进制
$ echo $((10#018))
18
附:
Constants with a leading 0 are interpreted as octal numbers. A leading 0x or 0X
denotes hexadecimal. Otherwise, numbers take the form [base#]n, where the optional
base is a decimal number between 2 and 64 representing the arithmetic base, and n is a
number in that base. If base# is omitted, then base 10 is used. When specifying n,
the digits greater< than 9 are represented by the lowercase letters, the uppercase
letters, @, and _, in that order. If base is less than or equal to 36, lowercase and
uppercase letters may be used interchangeably to represent numbers between 10 and 35.
- 可以指定数值的进制,格式为
base#number,比如二进制 2#110,八进制 8#6,十六进制 16#6,十进制 10#6 - 不指定数值进制时,
- 以 0 开头时,是八进制的数值,例如 017 等价于 8#017
- 以 0x 或 0X 开头时是 16 进制,例如 0x17 等价于 16#17
- 否则是十进制,例如 17 等价于 10#17

在bash脚本中遇到一个错误,当数值过大时不能作为算术计算的基数。问题出现在使用0开头的数字,bash将其解析为八进制导致。通过修改数字表示方式解决了问题。bash的ARITHMETIC EVALUATION允许指定数值的进制,如2#、8#、16#等,并规定了不同进制的解析规则。
3361

被折叠的 条评论
为什么被折叠?



