grep・sed・awkをパイプで繋ぐ!Linuxログから原因と不審IPを即特定
ログ調査のたびにエディタやGUIツールで開き、検索と目視を繰り返していませんか。ファイルが数百MBになると、開くだけで時間がかかります。この記事では、grep・sed・awk を パイプライン で繋ぎ、ターミナルだけで素早く絞り込み、加工、集計する方法を解説します。最後にアクセスログから「エラーが多いエンドポイント」と「怪しいIP」を数コマンドで洗い出す実践例も紹介します。コピーして試せる形で書いているので、手元のログで動かしてみてください。
なぜエンジニアにLinuxコマンドのパイプライン処理が必要なのか?
パイプライン (|) は、あるコマンドの出力を次のコマンドの入力に渡す仕組みです。UNIX の設計思想では「1つのことをうまくやる小さな道具を組み合わせる」ことが重視されてきました。検索は grep、置換は sed、列の処理は awk と役割を分け、必要に応じて繋ぎます。
この方式には実務上の利点が3つあります。
- サーバにログインしただけで、追加ツールなしに調査を始められる
- 大きなファイルでも、1行ずつ流れ作業で処理するため、メモリを圧迫しにくい
- 実行したコマンドをそのまま手順書やスクリプトにでき、チームで再現できる
GUIが悪いわけではありません。ただ、SSH 先のサーバにはGUIがないことが多く、調査の手順を他人に共有しにくい点が弱点です。コマンドなら、1行を共有するだけで同じ結果を再現できます。
まず押さえたい基本!grepによる高速フィルタリングと正規表現の勘所
grep は「条件に合う行を取り出す」コマンドです。まず覚えたいオプションは次の通りです。
| オプション | 意味 |
|---|---|
| -n | 行番号を表示 |
| -i | 大文字小文字を無視 |
| -v | 一致しない行を表示 (除外) |
| -c | 一致した行数を表示 |
| -r | ディレクトリを再帰的に検索 |
| -E | 拡張正規表現を使う |
| -A / -B / -C | 前後の行も表示 |
# ERROR または FATAL を含む行を、前後2行つきで表示
grep -nE "ERROR|FATAL" -C 2 app.log
# ヘルスチェックを除外して件数を数える
grep -v "/health" access.log | wc -l
正規表現では ^(行頭)、$(行末)、.(任意の1文字)、*(直前の0回以上の繰り返し)を押さえれば、多くの場面をカバーできます。-E を付けると | や + を、バックスラッシュなしで書けます。
注意点として、-P(Perl互換正規表現)は GNU grep の機能で、macOS 標準の grep など環境によっては使えません。チームで共有するコマンドは、まず -E の範囲で書くと互換性の問題を避けられます。また .gz に圧縮されたログは zgrep で、解凍せずに検索できます。
sedとawkで差をつける!行・列データの抽出と一括テキスト置換
sed は「行単位のストリーム編集」が得意です。代表例は置換 (s) と行の範囲指定です。
# 画面上だけで置換 (ファイルは変更されない)
sed 's/staging/production/g' config.txt
# 10〜20行目だけを表示
sed -n '10,20p' app.log
ファイルを直接書き換える -i は強力ですが、元に戻せません。GNU sed では -i.bak で、バックアップを残せます。macOS (BSD sed) は -i の直後に拡張子の指定が必須で、書き方が異なります。環境差があるため、まずは -i なしで結果を確認する習慣を付けてください。
awk は「空白などで区切られた列」を扱うのが得意です。デフォルトでは空白区切りで、1列目が $1、行全体が $0 です。
# 1列目と3列目だけを表示
awk '{print $1, $3}' access.log
# CSVの2列目が1000より大きい行を表示 (区切り文字は -F で指定)
awk -F, '$2 > 1000 {print $0}' data.csv
# 列ごとの合計を END で出力
awk -F, '{sum += $2} END {print sum}' data.csv
使い分けの目安は、行ごと置換するなら sed、列を見て条件分岐や集計をするなら awk です。awk は連想配列も持つため、後述のように sort | uniq -c なしで集計することもできます。
パイプ・リダイレクト・xargsを組み合わせて複数コマンドを自在に繋ぐ
パイプと合わせて覚えたいのがリダイレクトです。> はファイルへの上書き、>> は追記、2>&1 は標準エラー出力を標準出力にまとめます。
# 結果をファイルに保存しつつ、画面でも確認する
grep "ERROR" app.log | tee errors.txt | wc -l
集計の定番パターンは sort | uniq -c | sort -nr です。uniq は隣り合う同じ行しかまとめないため、先に sort が必要です。これを忘れると、集計結果がずれます。
# 出現回数の多い順に上位10件
cut -d' ' -f1 access.log | sort | uniq -c | sort -nr | head -10
xargs は、標準入力から受け取った文字列を別コマンドの引数に変換します。ファイル名に空白が含まれる場合に備え、find の -print0 と xargs -0 を組み合わせると安全です。
# .log ファイルから "timeout" を含む行を検索
find /var/log/myapp -name "*.log" -print0 | xargs -0 grep -n "timeout"
リアルタイム監視では tail -f app.log | grep --line-buffered "ERROR" のように、--line-buffered を付けます。付けないと出力がバッファに溜まり、表示が遅れることがあります。
実践シナリオ:アクセスログからエラー多発エンドポイントと特定IPを瞬時に抽出する
ここでは、Nginx や Apache で一般的な combined 形式のログを例にします。空白区切りで、1列目がクライアントIP、7列目がリクエストパス、9列目がHTTPステータスです。ログ形式を独自に変更している環境では列の位置がずれるため、まず head -3 access.log で実際の中身を確認してください。
最初に、5xx エラーが多いエンドポイントの上位を出します。
awk '$9 ~ /^5/ {print $7}' access.log \
| sed 's/?.*//' \
| sort | uniq -c | sort -nr | head -10
awk で5xx系だけを抽出し、sed でクエリ文字列を除去してパスごとに集約しています。?id=123 のようなパラメータが付いたままだと、同じエンドポイントが別物として数えられるためです。
次に、リクエスト数の多いIPを調べます。
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10
気になるIPが見つかったら、そのIPが何をしているかを絞り込みます。ここでは文書用のIPアドレス (203.0.113.5) を使います。
grep '^203.0.113.5 ' access.log | awk '{print $9, $7}' | sort | uniq -c | sort -nr | head
awk だけで集計することも可能です。
awk '$9 >= 500 {c[$7]++} END {for (p in c) print c[p], p}' access.log | sort -nr | head
この調査から「特定のIPがログインページに大量アクセスしている」といった傾向が見えれば、WAF 設定やレート制限の検討材料になります。ただし、リクエスト数が多いだけで攻撃と断定はできません。社内のプロキシや監視ツールを経由したアクセスも、同一IPに集約されるためです。User-Agent や時間帯など他の情報と合わせて判断してください。
サーバ作業で事故を防ぐ!安全にコマンドを実行・検証するためのチェックリスト
パイプラインは強力な分、破壊的な操作にも繋がります。本番サーバで実行する前に、次の点を確認してください。
- まず読み取り専用で試す: sed は
-iなしで、出力を確認してから反映します - バックアップを取る:
-i.bak(GNU sed) やcp file file.bakで、元に戻せる状態にします - xargs は echo で予行演習する:
xargs -0 echo rmのように、実行されるコマンドを先に表示します - 出力を絞る: 最初は
| headを付け、大量出力で端末やSSH接続が重くなるのを防ぎます - 元のログは直接編集しない: 解析用にコピーして作業します。ログローテーション中のファイルは特に注意が必要です
- 列番号と形式を確認する:
headで数行を見て、$7や$9が想定通りか確かめます - クォートを徹底する: 正規表現や
$を含む式は、シングルクォートで囲みシェルによる展開を防ぎます
さらに、パイプラインを少しずつ伸ばして書く方法も有効です。grep の結果を確認し、次に awk を足し、その結果を見て sort | uniq -c を足します。1段ずつ出力を確かめれば、間違いにすぐ気付けます。完成したコマンドは、コメントを添えてシェルスクリプトや社内Wikiに残すと、チームの調査手順として再利用できます。


