やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Bash整数確認

 値が整数であるかどうか確認する。

成果物

結論

IsInt() { test 0 -eq $1 > /dev/null 2>&1 || expr $1 + 0 > /dev/null 2>&1; }

よく見かけるexprだけの奴はバグがある。

 ネット上では以下コードで数値判定できるような記事を見かける。

IsInt() { expr $1 - 1 > /dev/null 2>&1; }

 しかし、-1のときfalseになってしまうバグがある。

$ IsInt -1 && echo 'Int' || echo 'NotInt'
NotInt

 それ以外の整数値なら負数であってもtrueになる。

$ IsInt -2 && echo 'Int' || echo 'NotInt'
Int

 原因は、expr -1 + 10になりfalseとなってしまうため。

対策

 対策は、計算結果が0になる場合の入力値のみ個別に判定すること。

IsInt() { test -1 -eq $1 || expr $1 + 1 > /dev/null 2>&1; }

 testで数値比較できない値が入るとエラー文言が出力されてしまう。それを> /dev/null 2>&1で消す。

IsInt() { test -1 -eq $1 > /dev/null 2>&1 || expr $1 + 1 > /dev/null 2>&1; }

 expr $1 + 1すると最大値が使えなくなってしまう。妥協案としてexpr $1 - 1に変更して最小値を使えないようにする。計算結果が0になる値の個別チェックもこれに伴い変更する。

IsInt() { test 1 -eq $1 > /dev/null 2>&1 || expr $1 - 1 > /dev/null 2>&1; }

 最大値、最小値、どちらも使えるようにしたい。そこでexpr $1 + 0とした。(expr $1 + 1でもexpr $1 - 1でもなく) 計算結果が0になる値の個別チェックもこれに伴い変更する。

IsInt() { test 0 -eq $1 > /dev/null 2>&1 || expr $1 + 0 > /dev/null 2>&1; }

 以上。

使い方

 true

IsInt 0 && echo 'Int' || echo 'NotInt'
IsInt 1 && echo 'Int' || echo 'NotInt'
IsInt 2 && echo 'Int' || echo 'NotInt'
IsInt -1 && echo 'Int' || echo 'NotInt'
IsInt -2 && echo 'Int' || echo 'NotInt'
IsInt 9223372036854775807 && echo 'Int' || echo 'NotInt'
IsInt -9223372036854775807 && echo 'Int' || echo 'NotInt'

 false

IsInt A && echo 'Int' || echo 'NotInt'
IsInt 0.1 && echo 'Int' || echo 'NotInt'
IsInt 9223372036854775808 && echo 'Int' || echo 'NotInt'
IsInt -9223372036854775808 && echo 'Int' || echo 'NotInt'

最大値:9223372036854775807

$ expr 9223372036854775807 + 1
expr: +: 計算結果は範囲外の値です
$ expr 9223372036854775806 + 1
9223372036854775807

最小値:-9223372036854775808

$ expr -9223372036854775808 - 1
expr: -: 計算結果は範囲外の値です
$ expr -9223372036854775807 - 1
-9223372036854775808

問題

  • 最小値〜最大値の範囲外はたとえ整数値であってもfalseになる
  • 浮動小数は対象外(falseになる)

最小値〜最大値の範囲外はたとえ整数値であってもfalseになる

 仕方ない。Bash言語仕様の限界。

浮動小数は対象外(falseになる)

IsInt 0.1 && echo 'Int' || echo 'NotInt' # NotInt

 IsInt浮動小数を渡せばfalseが返る。

 Bashでは浮動小数を扱えない。整数のみ。bcコマンドで扱えるが、Raspbianにはデフォルトでインストールされていない。また、.1のように最初の0を省略せねばならないなどのクセがある。

対象環境

$ uname -a
Linux raspberrypi 4.19.75-v7l+ #1270 SMP Tue Sep 24 18:51:41 BST 2019 armv7l GNU/Linux