awkコマンドの基本:行ごとに(そして列ごとに)データを処理する

今回は、awkコマンドの基本となる「行単位の処理」について説明する。これを押さえておかないと、使い方がさっぱりわからないだろう。

次のような空白区切りのデータを用意したとする。


% cat data.ssv
a b c d e
A B C D E
1 2 3 4 5
%

パターンに何も指定しなかった場合には「{}」の中に記述した処理は全ての行に適用される。次の例は、「入力された行データをそのまま出力する」という処理を実行したものだ。


% awk '{print}' data.ssv
a b c d e
A B C D E
1 2 3 4 5
% awk '{print $0}' data.ssv
a b c d e
A B C D E
1 2 3 4 5
%

「{print}」や「{print $0}」はパターンが指定されていないので、全ての行に対して実行される。「print」は、「行の内容をそのまま出力する」という命令だ。また、「$0」というのは入力された行データ全体を指している。「print」も「print $0」も、処理としては同じことを行う。

「$0」が行全体を指しているということから察した方もいるかもしれないが、「$1」や「$2」といった指定もできるようになっている。「$1」は1列目、「$2」は2列目を指す。次のように指定して実行すると、指定した列の内容だけが出力されることがわかるだろう。


% awk '{print $1}' data.ssv
a
A
1
% awk '{print $2}' data.ssv
b
B
2
%

また、「$1」と「$2」を並べて出力すると、以下のようにそのまま1列目と2列目がくっついたデータが出力される。


% awk '{print $1$2}' data.ssv
ab
AB
12
%

awkでは、空白がデフォルトの区切り文字だ。そのため、「print」の処理は少々興味深い動作をするようになっている。「$1」や「$2」はカンマで区切って指定することができ、その場合にはデフォルトの空白で区切られた状態で出力される。次のような感じだ。


% awk '{print $1,$2}' data.ssv
a b
A B
1 2
% awk '{print $1 " " $2}' data.ssv
a b
A B
1 2
%

「$1,$2」が「$1と$2のデータを空白で区切って出力する」という指定になる。awkでは文字列データを連続して記述した場合、結合して出力されるので、「$1 ” ” $2」という指定をすると、「$1,$2」と指定した場合と同じように空白区切りで出力される。

「連続で記述した文字列データが結合される」というケースは、ほかのプログラミング言語でもある。これはもう、こういうこともあるのだと覚えるしかない。

データを出力する方法として、「printf」という方法も紹介しておこう。「printf」はC言語のprintf(3)関数やコマンドで用意されているprintf(1)コマンドと同じような動きをする。フォーマットを指定して、データを出力するというものだ。例えば、次のように使用する。


% awk '{printf("%s %s\n",$1,$2)}' data.ssv
a b
A B
1 2
%

「”%s %s\n”」というのが、ここで言うフォーマットに当たる。「%s」は文字列、「\n」は改行を意味している。「”%s %s\n”,$1,$2」という指定なので、「$1” “$2”\n”」という出力が行われることになる。「print $1,$2」と同じだ。つまり、「print」では自動的に出力データの最後に改行指定である「”\n”」が含まれていることになる。printとprintfの違いは追求しすぎるとよくわからなくなってくるので、あまり深く考えないことをお薦めする。

数値データを桁指定して出力させる場合には、「printf」を使う必要がある。そうでなければ、「print」で事足りる。とりあえずこの2つの指定方法があることを覚えておき、選べるときは好きなほうを使ってもらえればと思う。

行データを処理することに特化していたsedコマンドと比べると、awkコマンドでは行に加えてさらに列という概念が入っていることがおわかりいただけただろう。そのため、スプレッドシートのようなデータの加工に向いているわけだ。「何列目」という指定が「$何列目」という形式で記述できることで、簡単に特定のデータを抜き出せるのはなかなか便利である。