awkの小技紹介3つ
CyberX データマイニングチーム エンジニアの遠藤です。
CyberXではソーシャルアプリ開発を行っていますが、
アプリを運用していると、
日々いろいろな大量のログが掃き出されています。
(Webアクセスログ、SQLのログ、phpの処理ログなど…)
その大量のログから有用な情報を取り出し集計・分析することは、
データマイニングチームにとっての重要な仕事です。
それでは、どのように集計するのか?
ログをそのままRDBMSのレコードに追加して処理するのもいいですが、
ログから何か”手速く”有用な情報を得たい!
というときにawkコマンドが有効です。
awkコマンドはUNIX上で開発されたフィールド指向のテキスト処理スクリプト言語で、
迅速なテキスト処理を実現します。
そこで、本記事では、
弊社で行っている様々な集計で実際に使用している
awkコマンドの小技3つを紹介します。
(なお、ここで紹介しているawkの処理系は全てgawkです。)
-----------------------------------------------------
[1] 二次元配列の表記法
awkでは擬似的に二次元配列を作成して行います。
(変数名)[【数字】,【数字】]
で表現します。
例
$ awk '{ i=1; j=1; hoge[i,j]=1000; print hoge[1,1]; }' test.log
1
一方、添字名を表示する際は、
「,」は省略されてしまい表示されないので、
どうしても添字名で「,」を使用したい場合は、
いったん「文字列」として認識させるとよいでしょう。
(awkでの配列における添字は、数字・文字列両方に対応します。)
例
$ awk '{ hoge[2,3]=1; for(index_id in hoge){print index_id;} }' test.log
23
$ awk '{ index_string="2,3"; hoge[index_string]=1; for(index_id in hoge){print index_id;} }' test.log
2,3
[2] 文字列との一致判定処理
文字列との一致判定処理は2種類あります。
(A) 最初から文字列を指定して、指定文字列行のみに対して処理するパターン
awk '/【文字列】/{ 【処理】 }'
なお、「【文字列】」の部分は正規表現も可能です。
例 ログに「Cy」の文字列があったらその文字列のみを表示する
$ cat test.log
Cyberx
Cyberagent
Sumzap
Applibot
Grenge
Cygames
Quunapp
CABeat
$ awk '/Cy/{print;}' test.log
Cyberx
Cyberagent
Cygames
(B) 処理中にif文で限定するパターン
awk '{ if($0 ~ "【文字列】"){ 【処理】 } }'
なお、"【文字列】"はawk中の変数に置き換えても動作します。
例 ログに「Cy」の文字列があったらその文字列のみを表示する
$ cat test.log
Cyberx
Cyberagent
Sumzap
Applibot
Grenge
Cygames
Quunapp
CABeat
$ awk '{character="Cy"; if($0 ~ character){ print; } }' test.log
Cyberx
Cyberagent
Cygames
(A)は固定文字列と一致判定させるとき、(B)は文字列が固定しないときに一致判定させるときにそれぞれ用いると効果的です。
[3] 時刻計算のための経過秒⇔日付・時刻の相互変換
《日にち・時刻→経過秒に変換》
mktime("【西暦】 【月】 【日】 【時】 【分】 【秒】")
《経過秒→日にち・時刻に変換》
strftime("【dateコマンドのフォーマット指示子】",【時刻変換したい変数】)
例 2012年8月1日0時0分0秒を経過秒に変換して、変換したものを日付・時刻に戻す
$ awk '{second=mktime("2012 08 01 00 00 00"); print second; date=strftime("%Y/%m/%d %H:%M:%S",second); print date;}' test.log
1343779200
2012/08/01 00:00:00
------------------------------
というように、ログの海から有用な情報をすぐに取り出す際はawkで!!!!