組込変数FPATの導入
通常、AWKのフィールド分割は組込変数FSにより分割を行います。この思想はとても便利で、一般的なファイルを処理するのには十分でした。ところが次に示すとおり、CSVファイルをうまく扱えません。
$ echo 'aaa,"bbb,ccc",ddd' |\ > awk -F, '{print $2}' "bbb
CSVファイルには「フィールド内にカンマを含む場合にはフィールドをダブルクォートで括る」というルールがありますので、第2フィールドは"bbb,ccc"になるはずですが、うまく取得できていません。こうしたCSVファイルも簡単に扱えるようにする仕組みとして導入されたのが、組込変数FPAT(フィールドパターン)です。
組込変数FPATを用いると、フィールド内にカンマが含まれている場合でも、次のようにきれいに扱うことができます。
$ echo 'aaa,"bbb,ccc",ddd' |\ > gawk -v FPAT='([^,]+)|(\"[^\"]+\")' '{print $2}' "bbb,ccc"
$ echo -e "aaa,\"bbb\nccc\",ddd" |\ > gawk -v FPAT='([^,]+)|(\"[^\"]+\")' '{print $2}' "bbb ddd
$ sudo tail -f /var/log/httpd/access_log |\ > gawk -v FPAT='([^ ]+)|(\"[^\"]+\")' '{print $NF} "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"'
$ echo 'aaa,"bbb,ccc",ddd' |\ > gawk '{patsplit($0,arr,"([^,]+)|(\"[^\"]+\")"); print arr[2]}' "bbb,ccc"
これにより、従来のAWKで扱いづらかったデータにも対応できるようになります。
多次元配列
従来のAWKも、疑似的に多次元配列を持つことはできました。この際はカンマが8進数表記で\034の文字列となり、配列のインデックスが連接として扱われるということは、本連載の前シリーズ「AWK処方箋」の最終回で説明しました。
$ awk 'BEGIN{arr[1, 2]="aaa";print arr[1, 2]}' aaa $ awk 'BEGIN{arr[1, 2]="aaa";print arr[1"\034"2]}' aaa
こうした疑似的な多次元配列でも十分便利でしたが、gawkでは正式な多次元配列(実際には連想配列なので、正しくは多次元連想配列)が導入されました。
$ gawk 'BEGIN{arr[1][2] = "aaa"; print arr[1][2]}' aaa
ただし、この多次元配列は従来の疑似多次元配列とは異なります。
$ gawk 'BEGIN{arr[1][2] = "aaa"; print arr[1, 2]}' (改行だけが表示される)
BEGIN { arr[1][1] = 300; arr[2]["Apple"] = 500; arr[3][1, 2] = 700; for (i in arr) { for (j in arr[i]) { print i, j, arr[i][j]; } } }
実行してみます。
$ gawk -f isarray1.awk 1 1 300 2 Apple 500 3 12 700
BEGIN { arr[1][1] = 300; arr[2]["Apple"] = 500; arr[3][1, 2] = 700; for (i in arr) { if (isarray(arr[i])) { for (j in arr[i]) { print i, j, arr[i][j]; } } } }
この多次元配列は便利なのですが、次のような場合に気をつける必要があります。
$ gawk 'BEGIN {split("a b c", arr[1]); print arr[1][1]}' gawk: cmd. line:1: fatal: split: second argument is not an array
エラーになりましたが、こういう場合には最初にarr[1][1]を空として生成しておく必要があります。
$ gawk 'BEGIN {arr[1][1] = "";split("a b c", arr[1]); print arr[1][1]}' a
今までのAWKに慣れてきた人には使いにくいかもしれませんが、行列計算や集計を行う際には便利でしょう。