前回紹介したサンプルスクリプトでは、配列に個別に文字列を代入していった。だが、あれはなかなかの「イモコード」だったと思う。awk的な書き方としては、空白区切りの文字列を用意しておき、それを一気に配列に変換するという方法が一般的だし、スマートだ。次のように記述すると、配列nに都道府県名が代入されるようになる。


        ken = "愛知県 青森県 秋田県 石川県 茨城県 岩手県 愛媛県 " \
        "大分県 大阪府 岡山県 沖縄県 香川県 鹿児島県 神奈川県 岐阜県 " \
        "京都府 熊本県 群馬県 高知県 埼玉県 佐賀県 滋賀県 静岡県 " \
        "島根県 千葉県 東京都 徳島県 栃木県 鳥取県 富山県 長崎県 " \
        "長野県 奈良県 新潟県 兵庫県 広島県 福井県 福岡県 福島県 " \
        "北海道 三重県 宮城県 宮崎県 山形県 山口県 山梨県 和歌山県"
        split(ken, n);

インデックスには、1から48までが割り当てられる。

awkでは、連続した文字列は結合される。そのため、変数kenには愛知県から和歌山県までの文字列が空白区切りになったものが代入されている。その次の行の「split(ken, n);」という処理で,変数kenが配列nに分割代入されていく。その際、インデックスは1から順に割り当てられるので、「n[1]」には愛知県が代入され、「n[2]」には青森県、「n[48]」には和歌山県が代入されることになる。

for制御構文

awkコマンドでは、grepやsedと違い、よく使われる制御構文を利用できる。今回のように配列を使うケースでは、for制御構文で処理するのが何かと便利だ。例えば、前回例示したスクリプトの場合、都道府県ごとに積算値を求める処理は、次のようにfor制御構文にまとめることができる。


        for (j=1; j<=48; j++)
                if ($2==n[j])
                        t[j] += 1;

注意する必要があるのは、配列のインデックスが1から始まることだ。プログラミング言語によっては、0から始まるものもあるが、awkの場合は1が始まりになっている。ここは、最初に押さえておいていただきたい。

この配列展開とfor制御構文を適用すると、前回取り上げた「searchzip2」は次のようになる。だいぶ短くシュッとまとまったのではないかと思う。


#!/bin/sh

key="$1"
awk '
BEGIN {
        ken = "愛知県 青森県 秋田県 石川県 茨城県 岩手県 愛媛県 " \
        "大分県 大阪府 岡山県 沖縄県 香川県 鹿児島県 神奈川県 岐阜県 " \
        "京都府 熊本県 群馬県 高知県 埼玉県 佐賀県 滋賀県 静岡県 " \
        "島根県 千葉県 東京都 徳島県 栃木県 鳥取県 富山県 長崎県 " \
        "長野県 奈良県 新潟県 兵庫県 広島県 福井県 福岡県 福島県 " \
        "北海道 三重県 宮城県 宮崎県 山形県 山口県 山梨県 和歌山県"
        split(ken, n);

        printf("====================================================\n")
        printf("\t\t住所から郵便番号を検索\n")
        printf("====================================================\n\n")
        printf("検索キーワード: %s\n\n","'$key'")
        printf("候補\t郵便番号 住所\n")
}

$2$3$4~/'$key'/ {
        ++i;
        printf("%03d\t%d (%s%s%s)\n",i,$1,$2,$3,$4);
        for (j=1; j<=48; j++)
                if ($2==n[j])
                        t[j] += 1;
}

END {
        printf("\n県別集計\n")
        for (j=1; j<=48; j++)
                if (0 != t[j])
                        printf("%s  \t%d件\n",n[j],t[j])
        printf("\n総候補数\t%d件\n",i)
}
' KEN_ALL_ROME.SSV

では早速、実行してみよう。まず、検索対象となるデータを確認しておく。


% head KEN_ALL_ROME.SSV
0600000 北海道 札幌市 中央区 以下に掲載がない場合 HOKKAIDO SAPPORO_SHI_CHUO_KU IKANIKEISAIGANAIBAAI
0640941 北海道 札幌市 中央区 旭ケ丘 HOKKAIDO SAPPORO_SHI_CHUO_KU ASAHIGAOKA
0600041 北海道 札幌市 中央区 大通東 HOKKAIDO SAPPORO_SHI_CHUO_KU ODORIHIGASHI
0600042 北海道 札幌市 中央区 大通西(1~19丁目) HOKKAIDO SAPPORO_SHI_CHUO_KU ODORINISHI(1-19-CHOME)
0640820 北海道 札幌市 中央区 大通西(20~28丁目) HOKKAIDO SAPPORO_SHI_CHUO_KU ODORINISHI(20-28-CHOME)
0600031 北海道 札幌市 中央区 北一条東 HOKKAIDO SAPPORO_SHI_CHUO_KU KITA1-JOHIGASHI
0600001 北海道 札幌市 中央区 北一条西(1~19丁目) HOKKAIDO SAPPORO_SHI_CHUO_KU KITA1-JONISHI(1-19-CHOME)
0640821 北海道 札幌市 中央区 北一条西(20~28丁目) HOKKAIDO SAPPORO_SHI_CHUO_KU KITA1-JONISHI(20-28-CHOME)
0600032 北海道 札幌市 中央区 北二条東 HOKKAIDO SAPPORO_SHI_CHUO_KU KITA2-JOHIGASHI
0600002 北海道 札幌市 中央区 北二条西(1~19丁目) HOKKAIDO SAPPORO_SHI_CHUO_KU KITA2-JONISHI(1-19-CHOME)
%

文字列から住所を検索すると、次のような結果が得られる。


% ./search_zip_2 次 郎
====================================================
                住所から郵便番号を検索
====================================================

検索キーワード: 次郎

候補      郵便番号 住所
001     9811526 (宮城県角田市神次郎)
002     9610091 (福島県白河市弥次郎窪)
003     9640808 (福島県二本松市木藤次郎内)
004     3212116 (栃木県宇都宮市徳次郎町)
005     9501433 (新潟県新潟市 南区次郎右エ門興野)
006     9591943 (新潟県阿賀野市次郎丸)
007     9391802 (富山県南砺市北野(次郎丸))
008     9188227 (福井県福井市次郎丸町)
009     9120067 (福井県大野市右近次郎)
010     9190745 (福井県あわら市次郎丸)
011     4313304 (静岡県浜松市 天竜区次郎八新田)
012     6760063 (兵庫県高砂市高砂町 次郎助町)
013     6408444 (和歌山県和歌山市次郎丸)
014     7711702 (徳島県阿波市阿波町 大次郎)
015     7992646 (愛媛県松山市神次郎町)
016     7871551 (高知県四万十市住次郎)
017     8140165 (福岡県福岡市 早良区次郎丸)
018     8900062 (鹿児島県鹿児島市与次郎)

県別集計
愛媛県     1件
鹿児島県    1件
高知県     1件
静岡県     1件
徳島県     1件
栃木県     1件
富山県     1件
新潟県     2件
兵庫県     1件
福井県     3件
福岡県     1件
福島県     2件
宮城県     1件
和歌山県    1件

総候補数    18件
%

当然、出力内容は前回の結果と同じだ。このように制御構文を含めるとawkのスクリプトもだいぶプログラミング言語っぽく見えてくると思う。あまりコードを複雑にしすぎるとawkを使う利点が損なわれてしまうが、シンプルさをキープできる範囲内であれば、こうした利用方法はかなり良いのではないだろうか。ぜひとも、使い方を覚えていただきたい。