grep | awk | sort | uniq を全部つなげる理由
〜ログ集計で「なぜこの並び順なのか」を丁寧に解説します〜
はじめに
ログ集計のワンライナーで、次のようなコマンドを見たことはないでしょうか。
grep "ERROR" access.log | awk '{print $1}' | sort | uniq -c
正直なところ、最初は
- なんとなく動いている
- とりあえずこの形をコピペしている
- どれか一つ省略しても良さそうに見える
と感じる方も多いと思います。
本記事では、なぜ grep | awk | sort | uniq をこの順番で全部つなげるのかを、IT初心者の方にも分かるように説明します。
全体の役割を一度に整理する
まず、それぞれのコマンドの役割を簡単に整理します。
| コマンド | 役割 |
|---|---|
| grep | 必要な行だけを抽出する |
| awk | 行の中から必要な項目を取り出す |
| sort | 行を並び替える |
| uniq | 同じ行をまとめる(集計する) |
重要なのは、uniq は並んでいないと正しく動かないという点です。
grep:集計したい行だけに絞る
ログファイルは、ほとんどが「今回欲しくない情報」です。
そのため、最初に grep で対象を絞ります。
grep "ERROR" access.log
これをしないまま後続処理をすると、
- awk が無駄に全行を処理する
- sort の対象が増えて処理が重くなる
といった問題が起きます。
grep はフィルタの入口だと考えると分かりやすいです。
awk:必要な項目だけを取り出す
ログ1行には、時刻・IP・URL・ステータスコードなど、さまざまな情報が含まれています。
集計したいのは、その中の一部だけ、というケースがほとんどです。
awk '{print $1}'
ここで不要な情報を落としておかないと、
- sort が不要に長い文字列を並び替える
- uniq が「同じ意味なのに別行」と判断してしまう
といったことが起こります。
sort:uniq のための必須準備
uniq は名前の通り「重複をまとめる」コマンドですが、隣り合っている行しかまとめません。
例えば、次の入力があるとします。
A
B
A
このまま uniq を実行すると、結果はこうなります。
A
B
A
正しくまとめるためには、事前に並び替えが必要です。
sort | uniq
この sort を省略するのは、ログ集計で最もよくある失敗の一つです。
uniq -c:数を数えるのは最後
ここまでで、
- 必要な行だけに絞られ
- 必要な項目だけになり
- 同じ値が隣り合った状態
が作られました。
その上で uniq -c を使うことで、初めて正しい件数が出ます。
uniq -c
まとめ
grep | awk | sort | uniq は、
- 余計な行を捨てる
- 必要な情報だけにする
- 正しく並べる
- 正しく数える
という処理の流れそのものです。
順番を変えたり、どれかを省略すると、
- 数が合わない
- 処理が遅くなる
- 気づかないまま誤集計する
といったトラブルにつながります。
おわりに
最初は「おまじない」に見えるパイプ処理ですが、
一つずつ役割を理解すると、ログ集計がかなり楽になります。