gawk の RS, RT を使う

GNU AWK (gawk) では組込変数 RS (Record Separetor) に正規表現を用いることができ、さらに組込変数 RT (Record Terminator) には RS で区切られた際のレコード区切り文字列が格納されます。 この拡張により以下のような場合に AWK が有効活用できます。

  • HTML や XML のような改行ではない特定の区切り文字を持つ構造化テキスト
  • 特定のキーワードで区切られたレコードを持つテキスト

まず、前者について説明します。

例えば、以下のようなテキストがあるとします。

$ cat test.html
<a>This is a.</a>
<b>
This is b.
</b>
<c>This is c.
</c>

このテキストの場合には正規表現で表した場合に </[^>]+> という部分がレコードの終端を示しています。 そこで、組込変数 RS に正規表現を用い、その際に用いられた区切り文字列を組込変数 RT から読みとってみます。

#! /bin/gawk -f

BEGIN {
    RS = "</[^>]+>";
}

{
    sub(/<[^>]+>/, "", $0);
    sub(/^\n+/, "", $0);
    sub(/\n+$/, "", $0);

    print "RT = ", RT;
    print "$0 = ", $0;
}

ここでは組込変数 RS は終端としての意味合いを明確にするため、後から必要なレコードの前に付く正規表現 <[^>]+> の部分や、レコードの両端に付いている余分な改行を削除しています。

では実行してみましょう。

$ gawk -f rt_test.awk test.html
RT =  </a>
$0 =  This is a.
RT =  </b>
$0 =  This is b.
RT =  </c>
$0 =  This is c.

このように構造化されているテキストに対して組込変数 RS に正規表現を用いることができると、AWK の活用の幅が広がることが分かります。

次に、特定のキーワードで区切られたレコードの例を見てみましょう。

$ cat test.txt
record1 = This is a. record2 = This is b.
record3 = This is c.

この例の場合には [ ]?record[[:digit:]]+[ ]?=[ ]? という部分がレコード区切りになります。 そこで、以下のようなスクリプトを準備しました。

#! /bin/gawk -f

BEGIN {
    RS = "[ ]?record[[:digit:]]+[ ]?=[ ]?";
}

{
    sub(/^\n+/, "", $0);
    sub(/\n+$/, "", $0);

    print "RT = ", RT;
    print "$0 = ", $0;
}

実行してみましょう。

$ gawk -f rt_test_2.awk test.txt
RT =  record1 =
$0 =
RT =   record2 =
$0 =  This is a.
RT =  record3 =
$0 =  This is b.
RT =
$0 =  This is c.

RT と $0 の関係が 1 つずれているように思われるかもしれませんが、これは先頭に組込変数 RS に相当する部分があるためです。

このように組込変数 RS に正規表現を用いることで今まで AWK では処理が難しかったテキストも処理できるようになります。

とはいえ、普通の Unix 系ツールや「シェル芸」で HTML や XML を扱う場合には以下のようにします。

$ cat test.html | tr -d '\n' | sed -r 's;</[^>]+>;\n;g' | sed -r 's;<[^>]+>;;'
This is a.
This is b.
This is c.

HTML や XML はどこで改行されているか不明なので、tr コマンドなどで一度すべての改行を削除することで Unix 系ツールで扱いやすくなります。 sed の正規表現はデフォルトでは少し特殊なので、-r を付けることで grep コマンドや AWK に近い正規表現が扱えるようにしています。

もうひとつの例は以下のように処理した方が楽かもしれません。

$ cat test.txt | sed -r 's;record[[:digit:]]+[ ]?=[ ]?;\n;g' | awk 'NF'
This is a.
This is b.
This is c.

最後の AWK の NF という部分は組込変数 NF が真、つまり 0 以外、つまりフィールドが存在する、つまり改行だけの行を除く、という意味です。

tag_gawk.pngtag_gawk.png