順番に読み進めながら学べます

awk — 集計とレポート

awkのBEGIN { } とEND { } が走る順番、s += $1で1列目を累計して合計を出す書き方、NRや { c++ } で件数を数える集計レポートの作り方を、図解とブラウザ端末で確認します。

処理の前後に走る — BEGIN と END

awkは各行を順に読みながら処理しますが、その前後に一度だけ実行したい処理をBEGIN { ... }END { ... }に書けます。BEGINは最初の行を読む前に 1 回、ENDはすべての行を読み終えた後に 1 回だけ走ります。見出しを先に出したり、集計結果を最後にまとめて出したりするときに使います。

BEGIN と END が走る順番
BEGIN { ... }行を読む前に 1 回見出しなどを先に出す{ 本体 }各行ごとに繰り返す1 行ずつ処理END { ... }全行を読んだ後に 1 回合計や件数を出す
BEGINは処理前に 1 回、本体は行ごとに、ENDは処理後に 1 回走ります。
書き方意味
BEGIN { ... }最初の行を読む前に 1 回だけ実行する
{ ... }1 行ずつ繰り返し実行する本体
END { ... }すべての行を読んだ後に 1 回だけ実行する
s += $11 列目の値を変数sに足し続けて累計する
NRここまでに読んだ行数(最終的に総行数)
{ c++ } END { print c }行ごとにcを増やし、件数を最後に出す
printf 'start\nmiddle\nend\n' > lines.txt          # 3 行の素材を作成
awk 'BEGIN { print "--- report ---" } { print $0 } END { print "rows:", NR }' lines.txt
# 先頭に見出し、最後に rows: 3 が付く

printf 'apple\nbanana\ncherry\n' > fruits.txtで 3 行の素材ファイルを作成してください。

cat fruits.txtで中身を確認してください。

awkを使い、BEGINで見出しの行を 1 回表示し、本体で各行をそのまま表示し、ENDNRを使って総行数を 1 回表示してください。

④ 画面の先頭に見出し、中央に 3 行、末尾に行数が出ていることを確認してください。(正しく実行できれば解説が表示されます)

Linux console
0 / 3 実行済み
Loading Linux Terminal...

合計と件数 — s += $1 と NR

awkでは変数を宣言なしで使え、数値はそのまま足し算できます。本体に{ s += $1 }と書くと、各行の 1 列目の値が変数sに足され続け、END { print s }で最後に合計が出ます。件数は読んだ行数を表すNRをそのままENDで出すか、{ c++ }でカウンタを増やしてEND { print c }で出します。これで売上の合計や件数といった集計レポートが作れます。

1 列目を累計して合計を出す
10 apple20 banana30 cherrys += $1 -> s=10s += $1 -> s=30END print s -> 60
s += $1が行ごとに 1 列目を足し、ENDで合計 60 を出力します。
printf '120 mon\n80 tue\n200 wed\n' > sales.txt   # 数値付き 3 行を作成
awk '{ s += $1 } END { print "total:", s }' sales.txt   # total: 400
awk 'END { print "days:", NR }' sales.txt               # days: 3

printf '50 a\n70 b\n30 c\n' > nums.txtで数値付き 3 行の素材を作成してください。

cat nums.txtで中身を確認してください。

awkの本体で 1 列目を変数に足し続け、ENDでその合計を 1 回表示してください。

④ 続けてawkENDNRを使い、行数(件数)を表示してください。

⑤ 合計と件数が画面に出ていることを確認してください。

Linux console
0 / 4 実行済み
Loading Linux Terminal...

件数をカウンタで数える — { c++ } END { print c }

NRは全行を数えますが、条件に合う行だけを数えたいときは本体でカウンタを使います。{ c++ }は読んだ行ごとに変数cを 1 ずつ増やし、END { print c }でその件数を出します。/pat/{ c++ }のようにパターンを付ければ、特定の文字列を含む行だけを数えられます。

一致行だけをカウンタで数える
pass xfail ypass z/pass/ c++ -> c=1fail -> 数えないEND print c -> 2
/pass/{ c++ }は一致行だけでcを増やし、ENDで件数 2 を出力します。
書き方意味
{ c++ }読んだ行ごとに変数cを 1 増やす
/pattern/{ c++ }patternを含む行だけでcを増やす
END { print c }最後に件数cを 1 回出力する
printf 'ok pay\nng pay\nok ship\n' > log.txt        # 状態付き 3 行を作成
awk '/ok/{ c++ } END { print "ok count:", c }' log.txt   # ok を含む行を数える -> 2

printf 'pass x\nfail y\npass z\n' > result.txtで状態付き 3 行の素材を作成してください。

cat result.txtで中身を確認してください。

awkpassを含む行だけカウンタを増やし、ENDでその件数を 1 回表示してください。

④ 表示された件数がpassを含む行の数と一致していることを確認してください。

⑤ 同じresult.txtawk 'END { print NR }' result.txt(全行数)とawk '/pass/{ c++ } END { print "pass count:", c }' result.txt(一致件数)を両方実行し、差を見比べてください。

Linux console
0 / 4 実行済み
Loading Linux Terminal...
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1BEGIN { ... }の中身はいつ実行されますか?

Q2awk '{ s += $1 } END { print s }' fは何を表示しますか?

Q3ENDブロックでNRを表示すると何が出ますか?