awkで合計とか平均とか算出する、ついでにgnuplotでグラフ化してみる
例えばイベントの実行時間を記録したログファイルから、個々のイベントの平均実行時間を算出したいとする.
例えば以下のようなawkを使って統計を取ることができる.
ログファイルは以下のような感じのものを想定.
#event exec_time foo 10 hoge 8.431 fuga 0.542 fuga 1.021 fuga 0.732 fuga 0.981 foo 30 bar 5.679 hoge 9.321 hoge 10.021 bar 6.091 foo 60 hoge 11.234 fuga 1.329
今回はついでに以下のようなグラフにしてデータの可視化も頑張ってみる.
awkで取った統計データをgnuplotでグラフ化する
冒頭のawk*1をcalc_avgというシェル関数にして、ログファイル(sample.log)の各イベント毎に取った統計を1つのファイルにまとめてgnuplotで描画する.
ログファイル中のイベント名でgrepをかけて、イベント毎に統計を取るイメージ.
分かりやすさ重視のつもりだけど、コードの繰り返しが見苦しい場合、
grep "hoge" $1 | calc_avg >> $plotfile grep "fuga" $1 | calc_avg >> $plotfile grep "foo" $1 | calc_avg >> $plotfile grep "bar" $1 | calc_avg >> $plotfile
は、
for log_msg in `cat $1 | awk '{ print $1 }' | sort | uniq` do grep "$log_msg" "$1" | calc_avg >> $plotfile done
とする方が良いかも.
これならイベントの種類が増えても大丈夫.
gnuplotのコードも工夫すれば繰り返し減らせるかもしれないけど、グラフはその場の用途に応じてすぐ変更がかかるから、あんまり苦労が報われない.
一応、
$ git clone https://gist.github.com/7660870.git $ cd 7660870 $ ./awk_avg.bash sample.log
とするとgraph_pngというディレクトリが生成されてその中に、合計、回数、最大、最小、平均の各種グラフが出来上がります.
生成される統計データはこんな感じ*2.
#label sum count max min avg hoge 39.007 4 11.234 8.431 9.75175 fuga 4.605 5 1.329 0.542 0.921 foo 100 3 60 10 33.3333 bar 11.77 2 6.091 5.679 5.885
awkやgnuplotのサンプルコードだと思ってもらえればこれ幸い*3.
行志向スクリプトawk
とにかく何でもASCIIテキストで扱いたいので、フィルタプログラムはどんどん覚えていきたい.
その中でawkは便利さを感じていたけれど、なかなかどうして身近なコマンドになるまでに時間がかかった.
AWK のスクリプトは、パターンとアクションの組を並べた形になっている。実行を開始すると、まず BEGIN パターンのアクションを実行する。以降、入力を読み込んでは、レコードセパレータ(デフォルトでは行末)までを1レコードとし、フィールドセパレータに従ってフィールドに分割してから、レコードがパターンにマッチするかを調べ、パターンにマッチしたらそのパターンに対応するアクションを実行する。一致するパターンが複数ある時は、該当するアクションが上から順に全て実行される。これを入力が尽きるまで繰り返す。入力が尽きたら、END パターンのアクションを実行し、終了する。
パターンとかアクションとか言う前に意識すべきは処理の単位たるレコードとフィールだと思うので、結局重要なのは、
レコードセパレータ(デフォルトでは行末)までを1レコードとし、フィールドセパレータに従ってフィールドに分割
の部分じゃないのかなと思う.
個人的には言語設計が"行志向"であるということを何かで読んでから急にコマンドとの距離感が縮まった.
ただ、行志向と言ってもデフォルトを切り替えることができる.
awk | デフォルト | 組み込み変数 |
---|---|---|
レコードセパレータ | 改行 | RS |
フィールドセパレータ | スペース | FS |
例えばこんな感じで各セパレータを切り替えられる.
$ echo 'hoge:fuga|foo:bar|' | awk 'BEGIN{FS=":"; RS="|"} { print $2 }'
この場合、"|"が改行と、":"がスペースと置き換わって、各レコードの第2フィールドにあたるfugaとbarがprintで表示される.
awkの組み込み変数の存在をはっきり認識すると急にやれることが増えた気がする.
組み込み関数とかもあるけどそこまで使い込めてない.
詳しくは、man awkを叩く.
gist記法
関係ないけど、1つのgistリポジトリに複数のファイルがある場合に、個々のファイルを指定してブログに表示したいんだけどできないんだろうか.
Github GistのPermalinkに合わせて[gist:7661278#file-calc_avg-awk]とかできたら良いのになぁ.
リンク切れやすいからやらないとか何かポリシーがあるのだろうか.