スクリプトがちょっと大きくなってきたり、同じような処理を繰り返し書くこ とがあったら、 AWKでも関数を定義して使うことができます。関数の定義は 次の書式で書きます。
function 関数名(引数の並び) {
awkの命令
awkの命令
...
awkの命令
return 戻り値
}
引数には数値でも文字列でも配列でもなんでも渡せます。returnの戻り値も、 数値と文字列が使えます。また再帰呼出しも出来ます。論より証拠、サンプル func.awkを見ましょう。
#!/usr/local/bin/gawk -f
# func.awk: 関数定義の例
BEGIN {
a = "OK"; b = "OK"; c = "OK";
print foo(1,2);
print a, b, c; # a,b,cは変化しない
print bar("AWKは", "便利だ");
print a, b, c; # a,b,cは変化しない
print "4! == " recursive(4); # 4! == 24
}
function foo(a, b, c) { # cは局所変数のつもり
c = a + b;
return c;
}
function bar(a, b, c) {
c = a b;
return c;
}
function recursive(a) { # 再帰呼び出しも可能
if (a <= 1)
return 1;
else
return a * recursive(a-1);
}
関数fooは数値を引数aとbで受けとって、その和を返す関数です。関数barは文 字列を引数aとbで受けとって、それを連結した文字列を返す関数です。
% ./func.awk
3
OK OK OK
AWKは便利だ
OK OK OK
4! == 24
%
どちらも仮引数にa、b、cを使っていますが、呼び出し側に同じ名前の変数が あってもそれは変化しません。つまり、 AWKの関数は Cと同じで値渡しなのです。
ところで、呼び出しのところでfooもbarも引数cに何も渡していません。これ は AWK流儀の局所変数の宣言です。実際には AWKの関数には局 所変数がありません。 AWKの関数の引数が値渡しであることを利用して、局 所変数代わりにしているのです。
本当の引数a,bに続いて局所変数用の引数cを記述しますが、このサンプルのよ うに、この2種類の変数を人間が区別しやすくするために間にスペースをたく さん置くことが慣習となっています。
この局所変数もどきがうまく動くのは、 Cと違って定義と呼出し時の引数の 数が一致しているかどうかを AWKが確認しないからですが、これはある意味 で危険なことも承知しておいたほうが良いと思います。
さて、配列を引数として渡すときは少し様子が違います。 Cと同じで、配列 だけは参照渡しなので、関数内で配列要素を書き換えると呼び出し 側でも値が変わります。
#!/usr/local/bin/gawk -f
# func2.awk: 関数に連想配列を渡す。
BEGIN {
for (i = 0; i < 4; i++)
a[i] = i;
print "元の配列の内容を表示";
for (i = 0; i < 4; i++)
print i, a[i];
foo(a);
print "関数foo内で書換えると?";
for (i = 0; i < 4; i++)
print i, a[i];
b["awk"] = "AWK"; b["perl"] = "PERL"; b["ruby"] = "RUBY";
print "元の文字列";
print b["awk"], b["perl"], b["ruby"];
bar(b);
print "関数bar内で細工すると";
print b["awk"], b["perl"], b["ruby"];
}
function foo(a, i) {
for (i = 0; i < 4; i++)
a[i] = -i;
}
function bar(a) {
a["awk"] = reverse(a["awk"]);
a["perl"] = reverse(a["perl"]);
a["ruby"] = reverse(a["ruby"]);
}
# 文字列strを逆転したものを返す("abc" --> "cba")
# str自体は変化しない。
function reverse(str, a, i, j, t) {
j = length(str);
if (j <= 0)
return;
split(str, a, //); # 文字列を配列に分解
for (i = 0; i < j/2; i++) { # 配列の中身を逆順にする
t = a[i]; a[i] = a[j-i]; a[j-i] = t;
}
t = "";
for (i = 0; i < j; i++)
t = t a[i]; # 配列を文字列に戻す
return t;
}
このスクリプトfunc2.awkを実行すると次のようになります。
% ./func2.awk
元の配列の内容を表示
0 0
1 1
2 2
3 3
関数foo内で書換えると?
0 0
1 -1
2 -2
3 -3
元の文字列
AWK PERL RUBY
関数bar内で細工すると
KWA LREP YBUR
%
OGURISU Osamu