しぐまろぐ

勉強したことや読んだ本について書きます。

シェル・ワンライナー160本ノック 問題8

問題8:ログの集計

access.logというログファイルについて、午前と午後それぞれの行数を求める。
ログファイルの中身は以下の通り。

183.YY.129.XX - - [07/Nov/2017:22:37:38 +0900]
192.Y.220.XXX - - [08/Nov/2017:02:17:16 +0900]
66.YYY.79.XXX - - [07/Nov/2017:14:42:48 +0900]
::1 - - [07/Nov/2017:13:37:54 +0900]
133.YY.23.XX - - [07/Nov/2017:09:41:48 +0900]

実戦でありそうな問題。

解答

$ awk -F: '{print $(NF-2)}' access.log | awk '{print $1<"12" ? "午前" : "午後"}' | sort | uniq -c
  • awk Fオプション : 区切り文字の変更。ここでは:に変更している。
  • NF : 各行の列数

最初のコロンを探してその後の2文字を取得する正規表現を考えようとしてうまくいかず。さらにログファイルの4行目が「::1」から始まるので、この方法ではうまく出力できないことになる。
結局、最初のawk部分は分からなくて解説を見た。後ろからコロンを探すのがポイント。awkのFオプションを使うことでややこしい正規表現も不要。

別解

別解1

grep正規表現を使う方法。

$ cat access.log | grep -o "..:..:.. +0900" | sed 's/:.*//' | awk '$1<"12"{print "午前"} $1>="12"{print "午後"}' | sort | uniq -c
別解2
$ sed -r 's@.*\[|\]|/@@g;s/:/ /' access.log | date -f- +%p | sort | uniq -c
  • sed rオプション : 「sed -E」と同じ。拡張正規表現を使うという宣言。
  • 's@.*\[|\]|/@@g;' : @が区切り文字で、\でエスケープしている。「[」以前の文字または「]」または「/」を削除するという意味。
  • date -f- : 「-f」で日付文字列をファイルから受け取れる。「-f-」ではパイプラインから受け取れる(ただしmacでは使えなかった)。
  • +%p : フォーマット指定子。%pはAMまたはPMを表す。

参考サイト

webkaru.net