2016年5月30日月曜日

シェルを電卓として使いたいとき

いろいろな方法が考えられる。

適当な言語のインタプリタを使う
真っ先に思い浮かぶ方法。よく使いそうなのというとPythonとかRuby(irb)とかGauche(gosh)とかだろうか。
プログラミング言語の高い表現力を享受できる代わりに(相対的に)巨大な言語がインストールされている必要がある。

計算用のコマンドを使う
bc、dc、exprなどがある。相対的に小さく、軽いが癖のあるものが多い。一番使いやすいのはbcだろうか。

awkを使う
確かにawkは計算ができる。だがシェル上に存在する問題すべてをawkで解決しようとするのはいかがなものか。「金鎚を手にするとあらゆる問題が釘に見える」とはこの謂か。もちろん文字列処理の一環として計算を行うならこれ以上のものはそうそうない。
awk 'BEGIN{print sin(30*3.1416/180)}'

シェルの機能を使う
$(())の中で多少の演算が可能である。これは別にBashやZshの拡張機能ではなくPOSIXで定義されているので(2.6.4 Arithmetic Expansionを参照)基本的にどのシェルでも使える。
echo $((256 + 998))
またこれはシェルスクリプトで変数のカウンタを回すときにも重用する。
count=`expr $count + 1`
ではなく
count=$((count + 1))
でいい。シェル組み込みの機能なので呼び出しのオーバーヘッドがない……はず。もっとも大した差ではないだろうけど。

[2016/5/31追記]
試してみたら大違いだった。
$ cat test.sh
count=0
while [ 1000000 -gt $count ]
do
    count=$((count + 1))
done

$ time sh test.sh 
real 0m8.446s
user 0m8.436s
sys 0m0.004s
に対し
$ cat test.sh
count=0
while [ 1000000 -gt $count ]
do
    count=`expr $count + 1`
done

$ time sh test.sh 
real 9m4.312s
user 0m29.381s
sys 1m19.182s

使用した環境はArch Linux, Bash4.3.42, expr (GNU coreutils) 8.25。ハードはCPU Intel Core i5 3475S, メモリ24GB。ちなみに何度か試したらbash(約8秒)よりzsh(約4秒)やbusybox sh(約3秒)のほうが高速だった。



なんでこんなことをまとめたかというと、仕事で文字列処理がしたくて、でもPCはWindowsだしソフトをインストールできないからWindows用busyboxを使うことにし、Powershellを立ち上げると横で電卓を使うのが面倒になりシェル上から計算もしたいなーと考えた結果である。シェルを手にするとあらゆる問題がシェル上の問題に見えてくるのだ。

Busyboxは便利だ。Powershellで
busybox.exe sh -l
するだけで立派な環境が手に入る。1MBもないバイナリの中にsedもawkもsortもuniqもcutもgrepもviさえも……もうなにも怖くない。

0 件のコメント:

コメントを投稿