「アクセスログのIPアドレスごとのリクエスト数を集計したいけど、手作業では限界がある」
Linuxサーバーの運用や障害対応でこうした場面に遭遇するのは日常茶飯事です。
この記事では、
awk コマンドの基本的な使い方から、列(フィールド)の抽出、条件による絞り込み、集計処理、そしてアクセスログ解析の実務例まで、現場で必要になるノウハウをまとめて解説します。RHEL 9.4 / Ubuntu 24.04 LTSで動作確認済みです。
この記事のポイント
・awk '{print $1}' でログの特定列を一発で抽出できる
・条件指定やBEGIN/ENDブロックで集計処理も可能
・アクセスログのIP別集計やエラー抽出など実務例を網羅
・sedとの使い分けは「列操作ならawk、置換ならsed」
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
awkコマンドとは?(テキスト加工の万能ツール)
awk は、テキストデータを「行」と「列(フィールド)」に分解して処理するコマンドです。名前はAho、Weinberger、Kernighanという3人の開発者の頭文字に由来します。Linuxに標準で入っている
gawk(GNU awk)が事実上のデファクトスタンダードです。ほとんどのディストリビューションで awk と入力すると gawk が呼ばれます。awkが得意なのは、次のような処理です。
・列の抽出:ログファイルから特定の列だけを取り出す
・条件フィルタ:特定の値を含む行だけを抜き出す
・集計・計算:数値の合計や平均を算出する
・テキスト整形:出力フォーマットを自由に変更する
基本的な使い方(フィールドの抽出)
1. 特定の列を表示する($1, $2, ...)
awkは入力を空白(スペースやタブ)で区切り、各列を$1(1列目)、$2(2列目)... と番号で参照できます。$0 は行全体を意味します。# /etc/passwd の1列目(ユーザー名)を表示する # awk -F: '{print $1}' /etc/passwd root bin daemon adm lp sync shutdown ...
-F: で区切り文字をコロン(:)に指定しています。指定しなければ、デフォルトの空白区切りが使われます。2. 複数の列を表示する
print に複数の $N を並べると、複数列を同時に抽出できます。# /etc/passwd から ユーザー名($1)と UID($3)を表示する # awk -F: '{print $1, $3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 ...
,)で区切ると、出力はスペース区切りになります。タブ区切りにしたい場合は "\t" を使います。# タブ区切りで出力する # awk -F: '{print $1 "\t" $3}' /etc/passwd root 0 bin 1 daemon 2 ...
3. 最後の列を取得する($NF)
列数が行ごとに異なるデータでも、$NF で最後の列を取得できます。NF(Number of Fields)は、その行のフィールド数を表す組み込み変数です。# /etc/passwd の最後のフィールド(ログインシェル)を表示する # awk -F: '{print $NF}' /etc/passwd /bin/bash /sbin/nologin /sbin/nologin ...
条件を指定して行を絞り込む
4. パターンマッチで行を選択する
awkでは'{print}' の前にパターン(条件)を書くと、条件に一致した行だけが処理されます。# "error" を含む行だけを表示する(grep相当の動作) # awk '/error/' /var/log/messages Apr 10 03:15:22 sv01 kernel: [error] disk I/O timeout on sda Apr 10 03:15:23 sv01 systemd[1]: Failed to start error-handler.service
{print} を省略した場合、awkはマッチした行をそのまま表示します。5. 数値の比較で絞り込む
フィールドの値を数値として比較できます。# UIDが1000以上のユーザーだけを表示する # awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd testuser 1000 miyazaki 1001 developer 1002
6. 文字列の比較で絞り込む
# ログインシェルが /bin/bash のユーザーだけを表示する # awk -F: '$NF == "/bin/bash" {print $1}' /etc/passwd root testuser miyazaki
7. AND / OR 条件を組み合わせる
&&(AND)や ||(OR)で複数条件を組み合わせられます。# UIDが1000以上 かつ ログインシェルが /bin/bash のユーザー # awk -F: '$3 >= 1000 && $NF == "/bin/bash" {print $1, $3}' /etc/passwd testuser 1000 miyazaki 1001
BEGIN / END ブロックで前処理・後処理を行う
8. BEGINブロック(データ処理の前に実行)
BEGIN ブロックは、入力データを読み込む前に1度だけ実行されます。ヘッダーの出力や変数の初期化に使います。# ヘッダー付きでユーザー一覧を表示する # awk -F: 'BEGIN {print "USER\tUID\tSHELL"} $3 >= 1000 {print $1 "\t" $3 "\t" $NF}' /etc/passwd USER UID SHELL testuser 1000 /bin/bash miyazaki 1001 /bin/bash developer 1002 /sbin/nologin
9. ENDブロック(データ処理の後に実行)
END ブロックは、すべての行を処理し終えた後に1度だけ実行されます。集計結果の出力に使います。# 行数をカウントする # awk 'END {print NR, "lines"}' /etc/passwd 45 lines
NR(Number of Records)は、処理した行番号を表す組み込み変数です。ENDブロック内では、最終行の行番号 = 全行数になります。集計・計算に使う(合計・平均・カウント)
10. 数値の合計を計算する
# dfコマンドの出力から、使用量($3列目)の合計を計算する # df -k | awk 'NR>1 {sum += $3} END {print "Used total:", sum, "KB"}' Used total: 8345612 KB
NR>1 で先頭のヘッダー行をスキップしています。sum += $3 で3列目の値を変数 sum に加算し、END ブロックで合計を出力します。awkの変数は宣言不要で、初期値は0です。11. 平均値を計算する
# vmstatの出力からCPU idle列の平均を計算する(5回取得) # vmstat 1 5 | awk 'NR>2 {sum += $15; count++} END {print "CPU idle avg:", sum/count, "%"}' CPU idle avg: 94.6 %
12. 特定の値ごとにカウントする(連想配列)
awkの連想配列を使うと、値をキーにしたカウントや集計ができます。これがawkの最も強力な機能の一つです。# /etc/passwd のログインシェルごとのユーザー数を集計する # awk -F: '{count[$NF]++} END {for (shell in count) print shell, count[shell]}' /etc/passwd /bin/bash 3 /sbin/nologin 38 /bin/sync 1 /sbin/shutdown 1 /sbin/halt 1 /bin/false 1
count[$NF]++ で、最後のフィールドの値をキーにした連想配列にカウントを加算しています。END ブロックの for (key in array) で全キーをループ処理します。実務で使うawkの応用例(ログ解析)
13. Apacheアクセスログから IP別リクエスト数を集計する
Apacheの combined ログ形式では、1列目がクライアントIPアドレスです。# IPアドレス別のリクエスト数を集計し、多い順にソートする # awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' /var/log/httpd/access_log | sort -rn | head -10 1523 203.0.113.xx 892 198.51.100.xx 445 192.0.2.xx 312 10.0.0.xx ...
14. HTTPステータスコード別の集計
Apacheのcombined形式では、9列目がHTTPステータスコードです。# ステータスコード別のリクエスト数を集計する # awk '{count[$9]++} END {for (code in count) print code, count[code]}' /var/log/httpd/access_log | sort 200 15234 301 892 304 2103 403 12 404 567 500 3
15. 特定の時間帯のアクセスだけを抽出する
# 午前3時台のアクセスだけを抽出する(障害発生時刻の調査) # awk '/12\/Apr\/2026:03:/' /var/log/httpd/access_log 203.0.113.xx - - [12/Apr/2026:03:15:22 +0900] "GET /index.html HTTP/1.1" 200 5432 198.51.100.xx - - [12/Apr/2026:03:15:23 +0900] "POST /api/login HTTP/1.1" 500 128 ...
16. レスポンスサイズの合計を計算する
combined形式の10列目がレスポンスサイズ(バイト)です。# 1日の総転送量を計算する # awk '{sum += $10} END {printf "Total: %.2f MB\n", sum/1024/1024}' /var/log/httpd/access_log Total: 1248.35 MB
printf を使うと、小数点以下の桁数を指定したフォーマット出力ができます。トラブルシュート:awkで困った時の対処法
17. 区切り文字が空白以外の場合
CSV(カンマ区切り)やコロン区切りのファイルは、-F オプションで区切り文字を明示的に指定してください。# CSV ファイルの2列目を表示する # awk -F, '{print $2}' data.csv # コロン区切り(/etc/passwdなど)の1列目を表示する # awk -F: '{print $1}' /etc/passwd # タブ区切りファイルの3列目を表示する # awk -F'\t' '{print $3}' data.tsv
18. シングルクォートとダブルクォートの注意
awkのプログラム部分はシングルクォートで囲むのが基本です。ダブルクォートで囲むと、シェルが$1 を変数展開してしまい、意図した動作になりません。# NG:ダブルクォートでは $1 がシェル変数として展開されてしまう # awk "{print $1}" /etc/passwd # OK:シングルクォートで囲む # awk '{print $1}' /etc/passwd
19. 「awk: fatal: cannot open file」が出た時
このエラーは、指定したファイルが存在しないか、読み取り権限がない場合に発生します。・ファイルの存在を確認する:
ls -l ファイル名 でパスが正しいか確認・権限を確認する:読み取り権限がなければ
sudo を付けて実行する・パイプ経由で渡す:ファイルを直接指定せず、
cat ファイル名 | awk '...' でも同じ結果が得られる(ただし、ファイル指定のほうが効率的)20. 複雑な処理はawkスクリプトファイルにする
ワンライナーが長くなりすぎた場合は、awkプログラムを別ファイルに書いて-f オプションで読み込めます。# awkスクリプトファイル(analyze.awk)の例 # BEGIN {FS=":"; print "USER\tUID\tSHELL"} # $3 >= 1000 {print $1 "\t" $3 "\t" $NF} # END {print "---"; print NR, "lines processed"} # スクリプトファイルを指定して実行する # awk -f analyze.awk /etc/passwd USER UID SHELL testuser 1000 /bin/bash miyazaki 1001 /bin/bash --- 45 lines processed
sedとawkの使い分け
sed と awk はどちらもテキスト処理の定番コマンドですが、得意分野がはっきり分かれています。・sed:「文字列を検索して置換する」処理が中心。設定ファイルの値の書き換えやコメントアウトに最適
・awk:「列(フィールド)を抽出・加工・集計する」処理が中心。ログ解析やCSVの加工に最適
迷ったときの判断基準はこうです。「特定の文字列を別の文字列に変えたい」なら sedコマンド、「列を切り出したい」「数値を集計したい」なら awk を使ってください。
パイプで両方を組み合わせるのも現場ではよく使うテクニックです。
# アクセスログから404エラーのURLだけを抽出し、クエリ文字列を除去する # awk '$9 == "404" {print $7}' /var/log/httpd/access_log | sed 's/?.*//' | sort -u /old-page.html /images/deleted.png /api/v1/deprecated
本記事のまとめ(awkコマンド早見表)
| やりたいこと | コマンド |
|---|---|
| 特定の列を表示する | awk '{print $1}' ファイル名 |
| 区切り文字を指定して列を抽出する | awk -F: '{print $1}' ファイル名 |
| 最後の列を取得する | awk '{print $NF}' ファイル名 |
| パターンに一致する行だけを表示する | awk '/パターン/' ファイル名 |
| 数値の比較で絞り込む | awk -F: '$3 >= 1000 {print $1}' ファイル名 |
| 数値の合計を計算する | awk '{sum += $1} END {print sum}' ファイル名 |
| 値ごとにカウントする(連想配列) | awk '{count[$1]++} END {for (k in count) print k, count[k]}' ファイル名 |
| IP別のアクセス数を集計する | awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access_log | sort -rn |
| ヘッダー行をスキップして処理する | awk 'NR>1 {print $1}' ファイル名 |
| awkスクリプトファイルを使う | awk -f スクリプト.awk ファイル名 |
'{print $N}' による列の抽出と、'{count[$1]++}' による集計の2つを押さえれば、ログ解析の大半はこなせます。sedが「文字列を書き換える道具」なら、awkは「データを読み解く道具」です。この2つを使いこなせば、Linuxのテキスト処理で困ることはほぼなくなります。
awkの出力、自信を持って読めていますか?
ログ解析や集計処理は、サーバー運用の現場で毎日のように求められるスキルです。awkの基本は理解できても、本番環境で「このログのどこを確認すべきか」を即座に判断するには、Linuxの仕組みを体系的に理解しておく必要があります。
ネットの切れ端の情報をコピペするだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
