講座「文系のためのawkプログラミング入門」
前回お話したように、awkの処理は
で構成されます。
今回はawkのテキスト処理の中心部である、パターン{アクション}の部分について、もう少し解説します。ここをよく理解することがawkを使いこなす上で決定的に重要になります。
本処理の部分である、パターン{アクション} では、awkはテキストを読みこみ、それがあるパターンに一致するなら、{ } の中の、アクションを実行します。しかし、awkはテキストを読み込むときに、ちょっとした処理を加えて、プログラマの仕事をやりやすくしてくれます。それが、テキストのレコードとフィールドへの分割です。
レコードというのは、デフォルトでは(つまりプログラマが特に指定しなければ…注1)、改行記号で区切られたテキストの一行ずつを指します。但し改行記号そのものは含まれません。
次に、awkは、このレコード(一行です)をさらに、フィールド(欄)に分割してくれます。フィールドへの分割は、デフォルトでは、つまりプログラマが何も指定しなければ、読み込んだテキストの一行を、半角空白かタブを区切りにして行われます。
(注1)こういうプログラマの業界用語も覚えておけば他の文献を読むときに役に立ちます、1、2回解説したら次からは業界用語に切り替えます
(注2)レコードの区切り方を改行記号以外のもので区切るように変更することも出来ますが、それについては後で解説することにしてここでは、レコードが、改行で区切られたテキストの一行ずつを意味すると理解して置いてください。
この二つの処理をawkは自動的に行います。プログラマの仕事は、awkのこの準備処理をうまく利用して、自分が行いたい独自の処理を記述する、と言うことになります。まとめれば、awkの本処理、パターン{アクション} は、
となります。1)、2)、はawkがやってくれます。プログラマの仕事は、3)の部分を記述することです。
それでは、プログラマは、こういうawkのレコードとフィールドへの分割という、awkの前処理をどういうふうに利用できるでしょうか(注3)。次の項目では、例を用いてその使い方を説明します。
(注3)awkがテキストをレコードに分割してくれることによって、プログラマは、テキストの一行ずつの処理だけを記述すればよいことになり、プログラミングそのものが大幅に簡素化されます。C言語やその他のプログラミング言語でテキストを処理する場合と比較するとき、テキスト処理のツールとしてのawkの優れた利点です。簡単なスクリプトで、どれくらい複雑な処理を行えるか、これから読者は実感されることでしょう。また、レコードのフィールドへの分割については、これをプログラマは利用しても良いし、利用しなくてもかまいません。適切に利用すれば、これもプログラミングを大幅に簡素化し作業効率をあげることができます。
たとえば次のようなテキスト(data2.txt)があるとします。
I am Taro You are Hanako He is Jiro She is Yoshiko
このようなテキストを処理するとき、awkは、まず最初の一行(レコード)を読み、それをフィールドに分割します。そして、フィールドは、$1、$2、--- などと名前を付けられます。つまり、その名前で呼び出して使うことが出来るようになります。これをより正確にいうと、レコードは、空白またはタブでフィールドに区切られ、最初のものから順番に、$1、$2、---という、変数に代入されるということです。変数と言うのは、数や文字列を格納しておく、入れもの、容器のようなものです。awkが独自に用意したこれらの変数(容器)を組込み変数と呼びます。図示すれば、つぎのようになります。最初のレコード、一行目を読んだときの状態です。
I am Taro I am Taro 第1フィールド 第2フィールド 第3フィールド レコード
$1 という変数(容器)のなかに、最初の文字列の「I」 が入っています。次の $2 という容器(変数)には、「am」 が、$3 には 「Taro」 が入っています。そして、大きい容器 $0 には、この一行、即ちレコードが、そのまま入っています。
二行目を読んだときには、次のようになります。
You are Hanako You are Hanako
三行目を読んだ時には、以下のようになります。
He is Jiro He is Jiro
このように、$1、$2、$3、という変数は、行を読むたびに、次々と中身を変えていきます。プログラマは、このawkがやってくれる前処理を利用して、色んなことができます。たとえば、各行の、三つ目の人名だけを取り出そうと思えば、次のようなスクリプトを書くことになります。これは、レコードを読むたびに、三つ目のフィールドを出力せよ、印字せよ、という意味になります。パターンが省略されているので、この命令は入力行の全てについて無条件に実行されます。
{print $3}
本当にうまく行くか、実験してみましょう。上に示した「data2.txt」 を作って、それを、おーくの友だちの入力ファイルリストにドラッグ&ドロップしてください。次に、Script欄のOne-Linerをクリックし、スクリプトの記入欄に上のスクリプトを記入してください。入力、Input欄は、File、出力先、Output欄は Screenを選択します。次のようになっていればいいです。
そしてRunボタンを押します。結果は次のようになりますね。
こうならずに、画面の上にERRORと出た場合は、注意深くスクリプトを見直してください。
次にもうひとつの例を試して見ましょう。今度は、ひとつだけ抜き出して出力するのではなく。一つを除外して他のものを出力します。例えば、各文の最後の語を除いて出力します。I am Taro ならば、三つ目の Taro だけを除いて出力します。このためにはどうすればいいかというと、
{print $1 $2}
です。先ほどのスクリプトを上のように修正して実行してください。つぎのようになるはずです。
ちょっと見にくいですね。ただ、$1と$2 を並べるだけでは上のように、連続して出力されます。間に半角空白をいれたいときは、"" で空白を囲んで、間に入れてやります。次のようにスクリプトを修正して、走らせてください。
{print $1 " " $2}
結果は、以下のようになるでしょう。
では、次のスクリプトでは結果はどうなるでしょうか?
{print $2 " " $1 " " $3 "?"}
一番目のフィールドと二番目のフィールドを入れ替え、最後にクエスチョンマークをつけます。疑問文ですね。うまく出来るかどうか、実際に走らせてください。以下のようになります。
文の先頭が大文字になっていないのが気になりますが、これを修正するのはもう少しawkについて学んでからです。自分で楽にやれるようになるでしょう。ここまで来れば、簡単なスクリプトで色んなことができるのが、分かりますね。こういう作業をawkを使わずにやろうと思えば、たとえばファイルを表計算ソフトに読みこみ、フィールドを手動で入れ替えるというような面倒なことをしなければなりません。上のスクリプトを、是非自分で実際に走らせて確認してください。さらにOutput欄をfiles(new)に変更して、実行してみて下さい。そうすれば、同じフォルダに「new_data.txt」という、ファイルが新しく作られ、処理結果が書き出されていることがわかるでしょう。awkはツール、道具です。自分で動かして見ることが大事です。道具はよく使って手に馴染ませなければなりません。手にしっくりと馴染んできたとき、awkの威力はますます発揮されます。
今回は、awkのレコード、フィールド、またフィールドを表す、$1、$2、などの組込み変数の一部について学びました。次回は、もう少し実用的な処理で、さらにフィールドについて学び、awkの学習の基礎を固めましょう。
(2005/06/20改定)