第 10 章「AIに任せる仕事を見極める」の 2 番目の角度: ログ解析はエージェントを呼ばず bash パイプ。
章のどの主張に対応するか
Linux コマンドラインでの一括処理 ── AI 利用料ゼロ。 同じ処理を AI エージェントに頼むと、約 60 分、AI 利用料約 $5。1,200 倍の速さ。
(章本文「実例: 数字で見る」より)
example-1 が「画像 1,000 枚を WebP 化」(I/O ヘビーな繰り返し処理)、 これは テキスト処理の繰り返し ── ログ解析を実演する。
やること
100,000 行(約 18 MB)の Apache combined log を生成して、6 種類の業務的な
クエリを awk + sort + uniq のパイプで解く:
| クエリ | 内容 |
|---|---|
| Q1 | 総リクエスト数 + ステータスコード分布 |
| Q2 | アクセス上位 10 IP |
| Q3 | 5xx エラーが起きた時間帯 |
| Q4 | 404 になった URL 上位 10 |
| Q5 | 攻撃疑いの IP(複数の攻撃 URL を試行) |
| Q6 | 1 分間のリクエスト数推移 |
すべて 0.04〜0.1 秒 で完了。
構成
example-2/
├── README.md
├── generate_log.py ── 100,000 行のサンプルログ生成
├── Makefile ── 6 クエリの bash パイプ
├── results.md
├── access.log ── 入力 (約 18 MB, .gitignore)
└── out/
├── q1-status.txt
├── q2-top-ips.txt
├── q3-5xx-hours.txt
├── q4-404-paths.txt
├── q5-attackers.txt
└── q6-rps.txt
実行
make clean && make all
なぜこれが「実例」になるのか
「ログから攻撃者を見つけて」「エラーの傾向を集計して」── これは 典型的に AI エージェントに頼みたくなる作業。でも:
エージェント方式(参考):
- 100,000 行のログをコンテキストに渡す → コンテキスト窓を超える
- ファイルを部分的に読ませる → 順次読みで遅い
- グレッパー的なツール呼び出しを LLM が書く → どうせ awk/grep
- 結果を集計させる → ハルシネーション(数値の)
- 1 回 60 分 / $5
bash パイプ方式(このフォルダ):
awk '$9 ~ /^5/ {print substr($4, 14, 5)}' access.log | sort | uniq -c | sort -rn | head
- LLM を呼ばない
- 100,000 行を 0.04 秒で集計
- LLM のハルシネーションが起きない(awk は嘘をつかない)
- そのまま cron に登録できる
これが章で言う「コードに凍結する」の典型例。
「LLM を呼ぶべき場合」との境界
# LLM を呼ばない:集計、フィルタ、上位 N 抽出
awk '$9 == 500' access.log | wc -l # 5xx の件数
sort | uniq -c | sort -rn # ランキング
# LLM を呼ぶべき:意図の判断、自然言語の要約
# 例: 「攻撃ログを見て、何の脆弱性を狙っているか教えて」
# → 攻撃 URL のパターン(`/.env`, `/wp-login.php`...)を Claude が解釈
集計はコード、解釈は AI ── これが境界。 このフォルダは集計側を最小実装で示す。
計測結果 — 第 10 章 example-2
実行環境: Linux 6.18 / awk + sort + uniq(GNU coreutils)
ログ規模
| 項目 | 数値 |
|---|---|
| 行数 | 100,000 行 |
| サイズ | 約 18 MB |
| 期間 | 2026-05-01(2 秒間隔の架空ログ) |
クエリ実行時間(主目的)
| クエリ | コマンド要約 | 実行時間 |
|---|---|---|
| Q1 ステータスコード集計 | awk '{c[$9]++}' |
0.05 秒 |
| Q2 上位 IP | awk | sort | uniq -c | sort -rn |
0.09 秒 |
| Q3 5xx の時間帯 | awk '$9~/^5/' | sort | uniq -c |
0.04 秒 |
| Q4 404 の URL | awk '$9==404' | sort | uniq -c |
0.05 秒 |
| Q5 攻撃 IP 検出 | awk + uniq + 集約 |
0.05 秒 |
| Q6 1 分ごとの RPS | awk | sort | uniq -c |
0.05 秒 |
| 合計 | 約 0.3 秒 |
100,000 行 × 6 クエリ = 600,000 行分の処理を 0.3 秒。
エージェント方式との比較
| 項目 | エージェント | bash パイプ |
|---|---|---|
| 6 クエリの実行 | 約 60 分 × 6 = 6 時間 | 0.3 秒 |
| 1 回の AI 利用料 | $5 × 6 = $30 | $0 |
| 結果の正確性 | ハルシネーション可能性あり | awk は計算ミスしない |
| 再現性 | プロンプト次第で揺れる | 同じ入力 → 同じ出力 |
| ログサイズの上限 | コンテキスト窓 | 無制限(ストリーミング) |
差は 約 70,000 倍。
実際の出力(抜粋)
Q1 ステータスコード分布
200 : 80,809 件 (80.8%)
304 : 6,646 件 (6.6%)
404 : 9,292 件 (9.3%)
500 : 3,253 件 (3.3%)
401 : 900 件 (0.9%)
403 : 100 件 (0.1%)
total: 100,000 件
Q2 上位 IP
5047 203.0.113.42 ← 突出
558 198.51.100.136
546 198.51.100.169
...
203.0.113.42 が 5,047 件(2 位の 9 倍)── 異常。
Q5 攻撃疑いの検出(2 種類以上の攻撃 URL を試行した IP)
203.0.113.42 攻撃 URL 5 種
Q2 で「異常に多い IP」、Q5 で「実際に攻撃 URL を試している IP」── これが 一致したので、フィルタ列に追加してブロック が次の自然な行動。
iptables -A INPUT -s 203.0.113.42 -j DROP
これも bash 1 行。
Q4 404 の URL 上位
1047 /
604 /static/style.css ← デプロイ漏れの疑い
418 /static/main.js ← 同上
362 /.env ← 攻撃試行
348 /config.php ← 同上
CSS / JS の 404 はデプロイの問題、.env などは攻撃。運用判断に
直結する数字 が秒で出る。
なぜ awk なのか
awk '{c[$9]++} END {for (s in c) print s, c[s]}' access.log
- 言語が小さい(20 分で覚えられる)
- どこにでもある(POSIX、cron に直接書ける)
- 巨大ファイルでも O(1) メモリ(行ストリーム)
- AI が出すコードを読める(短い、副作用が無い)
LLM に「awk で…」と頼むと 8 割は一発で動く。9 割の運用判断を これでカバーできる。
残り 1 割の「文字列の意味」「パターンの解釈」だけ、Claude に渡す。
来月の運用
*/15 * * * * make analyze >> /var/log/web-analytics.log 2>&1
0 9 * * 1 make analyze | mail -s "Weekly access report" admin@example.com
15 分ごとに実行 / 月曜朝にメールで届く ── すべて月額 0 円。
再現手順
make clean && make all
依存ゼロ(awk / sort / uniq は標準で入っている)。