awk
| 対応: | Bash 1.0(1989) |
|---|
『awk』はテキストをフィールド(列)単位で処理するプログラミング言語です。CSVやログファイルの集計・抽出・変換など、構造化テキストの処理で強力な能力を発揮します。
構文
awk [オプション] 'プログラム' [ファイル...]
awk -F 区切り文字 'プログラム' [ファイル...]
構文・変数一覧
| 構文 / 変数 | 概要 |
|---|---|
| '{print $1}' | 1番目のフィールドを表示します($0 は行全体)。 |
| -F ':' | フィールド区切り文字を指定します(デフォルトは空白)。 |
| NR | 現在処理中の行番号です。 |
| NF | 現在行のフィールド数です。$NF で最後のフィールドを参照できます。 |
| FS | フィールド区切り文字(Field Separator)です。 |
| OFS | 出力フィールド区切り文字(Output Field Separator)です。 |
| RS | レコード区切り文字(Record Separator、デフォルトは改行)です。 |
| BEGIN { } | ファイルを読む前に1度だけ実行されるブロックです。 |
| END { } | ファイルを読み終えた後に1度だけ実行されるブロックです。 |
| /パターン/ { } | パターンに一致する行にのみ処理を適用します。 |
サンプルコード
以下のファイルを例に説明します。
scores.txt
八神庵 85 Tokyo 草薙京 92 Osaka テリー・ボガード 78 Tokyo ブルー・マリー 95 Nagoya ゲーニッツ 88 Osaka
sales.csv
name,amount,region 八神庵,1200,east 草薙京,800,west テリー・ボガード,1500,east
各行の1番目のフィールドを表示します。
awk '{print $1}' scores.txt
八神庵
草薙京
テリー・ボガード
ブルー・マリー
ゲーニッツ
条件を指定して、2列目が90以上の行のみ表示します。
awk '$2 >= 90' scores.txt 草薙京 92 Osaka ブルー・マリー 95 Nagoya
条件に一致した行の特定フィールドだけを表示します。
awk '$2 >= 90 {print $1, $2}' scores.txt
草薙京 92
ブルー・マリー 95
『NR』で行番号付きで表示します。
awk '{print NR": "$0}' scores.txt
1: 八神庵 85 Tokyo
2: 草薙京 92 Osaka
3: テリー・ボガード 78 Tokyo
4: ブルー・マリー 95 Nagoya
5: ゲーニッツ 88 Osaka
『END』ブロックで数値を合計します(2列目を合計)。
awk '{sum += $2} END {print "Total:", sum}' scores.txt
Total: 438
『-F』で区切り文字を指定してCSVを処理します。
awk -F',' '{print $1, $2}' sales.csv
name amount
八神庵 1200
草薙京 800
テリー・ボガード 1500
『BEGIN』と『END』を使ってヘッダー・フッターを付けます。
awk 'BEGIN{print "=== Results ==="} {print $1, $2} END{print "=== End ==="}' scores.txt
=== Results ===
八神庵 85
草薙京 92
テリー・ボガード 78
ブルー・マリー 95
ゲーニッツ 88
=== End ===
パターンに一致する行を処理します(3列目が『Tokyo』の行のみ)。
awk '$3 == "Tokyo" {print $1, $2}' scores.txt
八神庵 85
テリー・ボガード 78
以下は発展的な使い方です。『seen』は連想配列で、行の内容をキーとして記録します。『!seen[$0]++』は「まだ記録されていない行」を意味し、重複行を除外する定番のイディオムです。
連想配列を使って重複を除去します。
awk '{print $3}' scores.txt | awk '!seen[$0]++'
Tokyo
Osaka
Nagoya
printf と OFS を使ったフォーマット出力
awk には C 言語ライクな『printf』が使えます。列の整形・固定幅出力に便利です。
printf で整形して出力します。
awk '{printf "%-20s %3d点\n", $1, $2}' scores.txt
八神庵 85点
草薙京 92点
テリー・ボガード 78点
ブルー・マリー 95点
ゲーニッツ 88点
OFS(出力フィールド区切り)を使って TSV → CSV に変換します。
awk 'BEGIN{OFS=","} {$1=$1; print}' scores.txt
八神庵,85,Tokyo
草薙京,92,Osaka
テリー・ボガード,78,Tokyo
ブルー・マリー,95,Nagoya
ゲーニッツ,88,Osaka
BEGIN で変数を初期化し、END で集計結果を表示します。
awk 'BEGIN{max=0} {if ($2 > max) {max=$2; name=$1}} END{print "最高点:", name, max}' scores.txt
最高点: ブルー・マリー 95
よくあるミス1: 数値と文字列の比較
awk 内の文字列比較に == を使うとき、数値と文字列の扱いに注意が必要です。"85" と 85 は等価として扱われますが、意図を明確にするために数値比較には数値リテラルを使う方法があります。
awk '$3 == "Tokyo" {print}' scores.txt
八神庵 85 Tokyo
テリー・ボガード 78 Tokyo
awk '$2 == 85 {print}' scores.txt
八神庵 85 Tokyo
よくあるミス2: クォート付きCSV
-F',' でCSVを処理するとき、クォートで囲まれたカンマに注意してください。awk -F',' は素朴なCSV分割なので "a,b","c" のようなデータには対応しません。その場合は gawk の FPAT や Python/Ruby を使います。単純なCSV(クォートなし)には -F',' で十分です。
awk -F',' '{print $1}' sales.csv
name
八神庵
草薙京
テリー・ボガード
よくあるミス3: printfの改行忘れ
printf は改行を付けないため、次の行と繋がってしまいます。
awk '{printf $1}' scores.txt
八神庵草薙京テリー・ボガードブルー・マリーゲーニッツ
改行を明示すれば正しく出力されます。
awk '{printf "%s\n", $1}' scores.txt
八神庵
草薙京
テリー・ボガード
ブルー・マリー
ゲーニッツ
概要
『$ awk』はシェル内で使える小さなプログラミング言語です。変数・条件分岐・ループ・配列・組み込み関数(gsub・split・substr・sprintf など)も使えます。複雑な処理は Python や Perl のほうが読みやすいですが、ワンライナーで済む集計・変換には awk が向いています。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。