awk コマンド

1つ以上のスペースで区切られた複数列のテキストデータをごにょごにょ処理するときに便利なツール。四則演算だとかもできる。

例えば以下のようなテキストファイルがあった場合、

1 2
3 4

以下のコマンドを実行すると

awk '{print $1 * $2;}' foo.txt
# または
cat foo.txt | awk '{print $1 * $2;}'

以下のように出力される。

2
12

区切り文字はデフォルトで1つ以上のスペースやタブが使えるみたい。スペースやタブが間にいくつ連続していても1つの区切りとみなされる。

ただ、awkの文法をなかなか覚えられず、なにかやりたいときにはPerlのワンライナーでも同じことができるので、自分はPerlを使ってしまいがち。

スポンサーリンク

HOWTO

コンマ区切り(CSV)で処理するには

-Fオプションで区切り文字を指定できる。

awk -F, '{print $2}'

行番号を出力するには

$ cat foo.txt | awk '{print NR " " $0;}'

行番号を1ではなく0から始めたい場合は

$ cat foo.txt | awk '{print NR-1 " " $0;}'

grepのようにパターンにマッチする行のみを抽出するには

正規表現をスラッシュで挟んで指定する。

awk '/pattern/'

とはいえ、これだけだったら自分はgrepコマンドのほうが慣れているので、 awkは使わない。

特定の列が特定の文字列になっている行のみを抽出するには

以下の例は1カラム目が foo の行のみを出力する。

$ awk '$1=="foo"'

逆に特定文字列の行を除外するには != を使う。

$ awk '$1!="foo"'

単純な出力ではなく、その行を対象になにかをさせるには以下のように書く。

$ awk '$1=="foo" { ... }'

特定の列がパターンにマッチする行のみを抽出するには

以下の例は2カラム目が foo で始まる行のみを出力する。

awk '$2~/^foo/'

sprintfのようなフォーマットで数字を出力するには

C言語の sprintf のような書式で出力するには、そのまま sprintf という関数が使える。

awk '{print sprintf("%04d", NR);}'

数字が書かれたテキストファイルからその合計/平均/最大値/最小値を計算するには

awkでできる大抵のことはPerlのワンライナーでもできるので、ここでは両方のやり方を紹介しておく。

以下のような1行に1つの数字が書かれたファイル(hoge.txt)があるとして、その合計や平均、最大値・最小値などを計算する方法。

228
516
512
549

合計を計算する例

awk '{sum+=$1}END{print sum}' hoge.txt
# または
cat hoge.txt | perl -nle '$sum+=$_; END{print $sum}'

平均を計算する例

awk '{sum+=$1}END{print sum/NR}' hoge.txt
# または
cat hoge.txt | perl -nle '$sum+=$_;$l++; END{print $sum/$l}'

ファイルの最後の行だけを無視して数字の合計を計算する例

head -n-1 hoge.txt | awk '{sum+=$1}END{print sum}'
# または
head -n-1 hoge.txt | perl -nle '$sum+=$_; END{print $sum}'

最大値を求める例

awk 'NR==1 {max=$1} {if($1 > max) max = $1} END {print max}' hoge.txt
# または
cat hoge.txt | perl -nle '(!defined($max) || $max<$_) and $max=$_; END{print $max}'

最小値を求める例

awk 'NR==1 {min=$1} {if($1 < max) min = $1} END {print min}' hoge.txt
# または
cat hoge.txt | perl -nle '(!defined($min) || $min>$_) and $min=$_; END{print $min}'

-> 数のリストの合計/平均を計算するには

テキストファイルの各行の文字数を求めるには

各行の、行末の改行を除く文字数を求める例。バイト数ではなくあくまで文字数である。

awkでの例とperlワンライナーでの例を載せておく。

$ cat hoge.txt | awk '{print length();}'
$ cat hoge.txt | perl -MEncode -nle 'print length(decode_utf8($_))'

その最大値を求める例。

$ cat hoge.txt | awk '{print length();}' | awk 'NR==1 {max=$1} {if($1>max) max = $1} END {print max}'
$ cat hoge.txt | perl -MEncode -nle '$l=length(decode_utf8($_)); $max=$l if $max<$l; END {print $max}'

または

$ cat hoge.txt | awk '{print length();}' | sort -rn | head -n1
$ cat hoge.txt | perl -MEncode -nle 'print length(decode_utf8($_))' | sort -rn | head -n1

テキストファイルの偶数番目の行のみまたは奇数番目の行のみを抽出するには

# 偶数行のみをパイプで抽出
awk 'NR % 2 == 0 { print $0; }'

# 奇数行のみをパイプで抽出
awk 'NR % 2 == 1 { print $0; }'

NR は行番号が自動で入っている変数で、1から始まる番号になっている。

出力でバッファリングをされないようにするには

fflush() を呼び出すとフラッシュしてくれる。

awk '{ print $0; fflush() }'

集計(?)

以下のような都市名と数字のペアが書いてあるテキストファイルがあったとして、都市ごとの数字の合計を計算したいとする。

Tokyo     10
Yokohama  8
Nagoya    4
Tokyo     12
Tokyo     31
Nagoya    7

以下のようなコマンドを実行すると

$ cat foo.txt | awk '{sum[$1]+=$2} END { for(key in sum){ print key, sum[key] } }'

以下のような出力が得られる。

Yokohama 8
Nagoya 11
Tokyo 53
このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。
スポンサーリンク