読者です 読者をやめる 読者になる 読者になる

カタカタブログ

SIerで働くITエンジニアがカタカタした記録を残す技術ブログ。Java, Oracle Database, Linuxが中心です。たまにRuby on Railsなども。

シェルで0始まり整数の演算をすると8進数演算になるので注意

Linux

シェルスクリプトで外部からデータを受け取り、簡単な四則演算をする処理があったのだが、特殊な数値の場合のみエラーとなる問題が発生した。よくよくデータを見ると、受け取る数値は”01”, “02”のように0始まりの固定2桁の数値フォーマットで、かつ数字が”08”、”09"のときだけエラーとなっていた。

結論から言うと、0始まりの数値を演算するときは8進数となり0〜7以外の数値(8,9)を使うとエラーになるためだった。

bashの場合

7以下の数値は8進数演算でも計算結果は正しい

$ echo $((01+01))
2
$ echo $((05+05))
10

08, 09を使うとエラー

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

cshの場合

cshの場合も同様。

7以下の数値の場合はOK

% @ a = 01 + 05
% echo $a
6

08, 09の場合はエラー

% @ a = 01 + 08
@: Badly formed number.

cshの場合はエラーメッセージがややわかりづらい。

その他の算術用コマンド

exprコマンドは0始まりでも10進数で演算してくれるよう

$ expr 08 + 09
17

bcコマンドも正しく10進数で計算してくれるよう

$ echo "01 + 08" | bc
9

いっそsedで先頭0を除去してしまう

いっそsedコマンドで0始まりの数値を通常の数値に直してしまう。以下のコマンドで修正できる。先頭以外の0は影響なし。下のコマンドで直したあとに計算すれば10進数で計算してくれる。

$ echo "08" | sed -e 's/^0\+\([0-9]\+\)$/\1/'
8
$ echo "008" | sed -e 's/^0\+\([0-9]\+\)$/\1/'
8
$ echo "123" | sed -e 's/^0\+\([0-9]\+\)$/\1/'
123
$ echo "01010" | sed -e 's/^0\+\([0-9]\+\)$/\1/'
1010

まとめ

シェル変数の計算は0始まりで8進数演算になるが、exprやbcのような算術用のコマンドだと0始まりでも10進数で計算してくれるので、入力データが0始まりで正しく10進数計算させたい場合は、注意が必要。先頭の0をテキスト処理で削除するか、exprやbcなどの算術用コマンドで計算する必要がある。

以上!