awk - 表計算が得意なインタープリタ


awkテキスト処理が得意なインタープリタ言語で、簡単に表計算をさせたりできます。

例えば、

% ypcat passwd | awk -F: '{print $1,$5}'

のようにすると、ypcat passwd の出力の : を区切り文字とした場合の第一フィールドの要素と第五フィールドの要素を出力します。-F でフィールドセパレータ(区切り文字)を指定しています。デフォルトでは空白文字、タブ文字が区切り文字となります。ワイルドカード として展開されてしまいそうな気がしたら " " のようにダブル、またはシングルクォーテーションで挟むなどして展開されないようにしましょう。

awk は基本的にループして1行ずつ処理をしているわけですが、 最初と最後にアクションを実行できるように、 BEGIN と END という特殊なパターンが用意されています。 BEGIN の直後に来るアクションは対象となるファイルの最初の行が読み込まれる前に実行されるもので、 END の直後にくるアクションは最後の行への処理が終わった後に実行されるものです。

% ypcat passwd | awk -F: 'BEGIN{i=0}{i++}END{print i;}'

とすると i の初期値を 0 として、1行読み込むたびに i をインクリメントして、最後に i を出力します。つまり、行数を数えます。 ただし、変数は初期化しなくても、デフォルトで 0 に設定されますので、BEGIN{ i=0 } は正直意味がありません。 また、awk の組み込み変数として NR という変数があり、これは現在何番目のレコード(行)を処理しているかをカウントしています。なので先ほどの例は、全く無意味です。 NF という組み込み変数もありまして、これは処理中のレコードにいくつのフィールドがあるかを記憶してます。 ついでに FS という組み込み変数もありまして、フィールドセパレータが設定されています。 プログラム中で設定しなおすことも可能です。

例えば、

a 23 54 12
b 30 78 77
c 59 90 2
d 21 8 3

という内容のファイルがあったとすると

% awk '{sum=0;for(i=2;i<NF;i++){sum+=$i;}ave=sum/(NF-1);print ave;sum_ave+=ave}
END{print "END:",sum_ave/NR;}' [filename]

で一行ずつの数字部分の平均、最終的にそれら平均全体の平均を出力します。 少し解説しますと、$i は i が 2 のとき $2 となり、第2フィールドの値を返します。 for ループで繰り返すことにより、sum は $2 + $3 + $4 ... 最終フィールドまで、の値になります。 for のほかにももちろん if や while などもあります。 srand(), rand() のコンビで乱数を発生させたりもできます。 その辺を書くときりがないのでこれ以上は書きません。

コマンドラインでプログラムを書くには長すぎる場合には、ファイル中にプログラムを記述し、

#!/usr/bin/awk -f
{
sum=0;
for(i=2;i<NF;i++){
    sum+=$i;
}
ave=sum/(NF-1);
print ave;
sum_ave+=ave;
}
END{print "END:",sum_ave/NR;}
% awk -f [awkfile] [filename]

のようにプログラムファイルを指定することで実行もできます。

#!/usr/bin/awk -f をファイルの先頭に書いたので、chmod でそのファイルに実行許可を出すことにより、

% ./[awkfile]

のようにして実行することも可能です。

これくらいならまだいいですが、もっと複雑な処理をする必要がある場合は、 awk ではなく perl を使ったほうが楽に作れます。 本当に簡単な処理だけならば awk のほうが楽に作れますが。

より詳しくは awk のページ等を参照したほうがよいでしょう。
また、gawk (GNU awk) というものもあります。こちらのほうが高機能で日本語を扱うこともできます。 The GNU Awk User's Guideが参考になります。


xrea