こんにちは、河野です。
今日もログネタです。1週間毎に保存されたログを日ごとに分けたいなと思ったので、awkでやってみました。
ログファイルはこんな感じです。わかりやすくするため1日辺り1行のログにしてみました。
| 1 2 3 4 5 6 7 8 | $ cat weekly.log 192.168.1.100 - - [19/Nov/2012:03:22:36 +0900] "GET / HTTP/1.1" 301 178 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.000 192.168.1.100 - - [20/Nov/2012:03:22:41 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.006 192.168.1.100 - - [21/Nov/2012:03:22:41 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 192.168.1.100 - - [22/Nov/2012:03:23:31 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 192.168.1.100 - - [23/Nov/2012:03:25:15 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 192.168.1.100 - - [24/Nov/2012:03:25:15 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 192.168.1.100 - - [25/Nov/2012:03:25:15 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 | 
これを、yyyy-mm-dd.log として7日分にしたいと思います。
日付を取得する
まずは、日付部分を取得したいと思います。awkの動作は、awkスクリプトの実行ファイルにしてみます。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ cat split_by_date #!/usr/bin/awk -f {     date = substr($4, 2, 11)     print date } $ cat weekly.log | ./split_by_date 19/Nov/2012 20/Nov/2012 21/Nov/2012 22/Nov/2012 23/Nov/2012 24/Nov/2012 25/Nov/2012 | 
日付を変換する
ちゃんと日付が取得できました。フォーマットが異なるので変換してみます。とりあえず月の表示がアルファベットですが、そこはいったんそのままで。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ cat split_by_date #!/usr/bin/awk -f {     date = substr($4, 2, 11)     split(date, params, "/")     formatted_date = params[3] "-" params[2] "-" params[1]     print formatted_date } $ cat weekly.log | ./split_by_date 2012-Nov-19 2012-Nov-20 2012-Nov-21 2012-Nov-22 2012-Nov-23 2012-Nov-24 2012-Nov-25 | 
このファイルだけに限れば、Novを11にするだけで解決するんですが、ちゃんと対応したいと思います。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $ cat split_by_date #!/usr/bin/awk -f function num_month(alpha_month) {     return index("__,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", alpha_month) / 4 } {     date = substr($4, 2, 11)     split(date, params, "/")     formatted_date = params[3] "-" num_month(params[2]) "-" params[1]     print formatted_date } $ cat weekly.log | ./split_by_date 2012-11-19 2012-11-20 2012-11-21 2012-11-22 2012-11-23 2012-11-24 2012-11-25 | 
ちゃんと変換できました!関数の仕組みは、連結した文字列からindexで位置を取得し、それを4で割っています。最初にアンダースコアを付けて、結果の数字が1~12になるよう調整しています。
ただ、もう少しだけ調整が必要で、1~9月までは1桁になってしまうので、2桁にする必要があります。sprintfを使います。
| 1 2 3 4 5 6 7 8 9 10 11 12 | $ cat split_by_date #!/usr/bin/awk -f function num_month(alpha_month) {     return index("__,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", alpha_month) / 4 } {     date = substr($4, 2, 11)     split(date, params, "/")     month = sprintf("%02d", num_month(params[2]))     formatted_date = params[3] "-" month "-" params[1]     print formatted_date } | 
個別のファイルに保存する
さて、日付が取得できるようになりましたので、後はログを日付別のファイルに保存するだけです。awkでも、シェルと同じようにリダイレクトが使えるので、受け取った行を全部日付のファイルに流し込むだけでOKです。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $ cat split_by_date #!/usr/bin/awk -f function num_month(alpha_month) {     return index("__,Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", alpha_month) / 4 } {     date = substr($4, 2, 11)     split(date, params, "/")     month = sprintf("%02d", num_month(params[2]))     filename = params[3] "-" month "-" params[1]     print $0 >> filename ".log" } $ cat weekly.log | ./split_by_date | 
ちゃんとログがリダイレクトされたため、今までと異なり何も出力されていません。ファイルに保存されているか確認してみます。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $ ls -1 2012-11-19.log 2012-11-20.log 2012-11-21.log 2012-11-22.log 2012-11-23.log 2012-11-24.log 2012-11-25.log split_by_date weekly.log $ for file in 2012*.log; do echo $file; cat $file; echo ; done 2012-11-19.log 192.168.1.100 - - [19/Nov/2012:03:22:36 +0900] "GET / HTTP/1.1" 301 178 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.000 2012-11-20.log 192.168.1.100 - - [20/Nov/2012:03:22:41 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.006 2012-11-21.log 192.168.1.100 - - [21/Nov/2012:03:22:41 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 2012-11-22.log 192.168.1.100 - - [22/Nov/2012:03:23:31 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 2012-11-23.log 192.168.1.100 - - [23/Nov/2012:03:25:15 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 2012-11-24.log 192.168.1.100 - - [24/Nov/2012:03:25:15 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 2012-11-25.log 192.168.1.100 - - [25/Nov/2012:03:25:15 +0900] "GET / HTTP/1.1" 200 26994 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)" "-" 0.003 | 
ちゃんと分かれて保存されました!
linuxで使えるコマンドをパイプとリダイレクトで繋ぐだけでは、異なるファイルに保存するのはちょっと大変です。かといって、PythonやRubyなどLLを使うほどでは…という時にはawkが使えると思います!

 
						
Comments
とても参考になりました。ありがとうございます。