【bash】コマンドラインで四則演算をする
シェルスクリプトは十分有用な言語といえるが、ただ一つ重大な欠点がある。実は四則演算が単純な式でできないのだ。
たとえば、pythonで1/3を計算して表示するには、たった1文次のようにすればよい。
print 1.0/3.0
ただし1/3としてはならない。なぜならば1/3には整数型しかあらわれず、演算結果も整数の範囲でしか返ってこないからだ。つまり「print 1/3」では「0」と表示される。
このように同じスクリプト言語にもかかわらず、bashではこのようなことはできない。
$ echo 1.0/3.0
1.0/3.0
つまり、文字列「1.0/3.0」が返ってくる。
一応計算する方法はある。まず、ループでカウンタをインクリメントする、カウンタに1を足すような、整数の範囲で済む計算の場合、「$(( ))」でくくれば計算が実行される。
$ echo $((1+3))
4
ただし、これで計算できるのは整数型のみで、最初に出した1/3のようなものはうまくできない。
$ echo $((1/3))
0
しかも1.0/3とすると構文エラーとなりそもそも計算がまわらない。
小数も計算する方法はある。bcというコマンドとパイプ処理を使う方法だ。
bcコマンドは数式を受け取って計算を実行するコマンドだ。とはいえ引数に数式をとることができず、次のようにechoで出した数式をパイプで渡すか、別ファイルに数式を書いて読ませなければならない。
$ echo 'scale=3; 1.0/3' |bc
.333
これにも注意点があり、小数を扱う場合は小数点以下の桁数をscaleで指定してやる必要があり、それ以下は切り捨てられる。指定しなければ整数となり、小数点以下はまるまる切り捨てられる。
また、1の位が0の場合は省略され上記のように小数点から始まってしまう。スクリプト内で使う場合で表記をそろえる必要がある場合は、さらにパイプを連ねて出力を変換する必要がある。たとえばsedで処理する場合は次のようにする。
$ echo 'scale=3; 1.0/3' | bc | sed -e 's/^\./0\./g'
0.333
sedは文字列の置換、削除など多くの用法がある有用なコマンドだ。評価式を引数に与えて処理するのだが、's/hoge/huga/g'で「hogeをhugaに置き換える」、's/^huga/hoge/g'のように^を付けると「先頭のhugaのみをhogeに置き換える」という意味になる。また「.」は任意の1文字という意味になる特殊文字なので\でエスケープしている。なので上記コマンドで「先頭の『.』を『0.』と置き換える」ということを意味する。
一方、「パイプなんてよくわかんない可読性が悪い、見栄えが悪い」という場合は、何かしらのインタープリタにコマンドを直接与えるという方法がある。たとえばpythonの場合-cオプションでpythonのコマンドを直接実行できるので、桁数を指定しなければ次で計算結果は得られる。
$ python -c 'print 1.0/3.0'
0.333333333333
luaの場合は以下のようになる。
$ lua -e 'print(1.0/3.0)'
0.33333333333333