awk コマンド 2015/06/22
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)で処理するには 2014/08/10
-F
オプションで区切り文字を指定できる。
例
awk -F, '{print $2}'
行番号を出力するには 2016/10/23
例
$ cat foo.txt | awk '{print NR " " $0;}'
行番号を1ではなく0から始めたい場合は
$ cat foo.txt | awk '{print NR-1 " " $0;}'
grepのようにパターンにマッチする行のみを抽出するには 2015/06/22
正規表現をスラッシュで挟んで指定する。
awk '/pattern/'
とはいえ、これだけだったら自分はgrep
コマンドのほうが慣れているので、
awk
は使わない。
特定の列が特定の文字列になっている行のみを抽出するには 2017/02/10
以下の例は1カラム目が foo
の行のみを出力する。
$ awk '$1=="foo"'
逆に特定文字列の行を除外するには !=
を使う。
$ awk '$1!="foo"'
単純な出力ではなく、その行を対象になにかをさせるには以下のように書く。
$ awk '$1=="foo" { ... }'
特定の列がパターンにマッチする行のみを抽出するには 2015/07/05
以下の例は2カラム目が foo
で始まる行のみを出力する。
awk '$2~/^foo/'
sprintfのようなフォーマットで数字を出力するには 2013/10/18
C言語の sprintf
のような書式で出力するには、そのまま sprintf
という関数が使える。
awk '{print sprintf("%04d", NR);}'
数字が書かれたテキストファイルからその合計/平均/最大値/最小値を計算するには 2015/02/04
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}'
テキストファイルの各行の文字数を求めるには 2015/09/29
各行の、行末の改行を除く文字数を求める例。バイト数ではなくあくまで文字数である。
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
テキストファイルの偶数番目の行のみまたは奇数番目の行のみを抽出するには 2014/03/17
# 偶数行のみをパイプで抽出
awk 'NR % 2 == 0 { print $0; }'
# 奇数行のみをパイプで抽出
awk 'NR % 2 == 1 { print $0; }'
NR
は行番号が自動で入っている変数で、1から始まる番号になっている。
出力でバッファリングをされないようにするには 2014/07/09
fflush()
を呼び出すとフラッシュしてくれる。
awk '{ print $0; fflush() }'
集計(?) 2015/09/03
以下のような都市名と数字のペアが書いてあるテキストファイルがあったとして、都市ごとの数字の合計を計算したいとする。
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