ENDパターンに対応するアクションがfor文に囲まれたので少しわかりづらくなった。これを解消する手法として,関数を使うのが有効である。該当部分を切り取り,その内容を関数とするのである。そして,もともとそれがあったところへは,関数を呼び出す命令を書いておく。
#!/usr/local/bin/gawk -f { for (j = 1; j <= 2; j++) { data[FNR,j] = $j } } END { for (j = 1; j <= 2; j++) { subroutine(j) } } function subroutine(j, i, mean, variance, sd) { mean = variance = 0 for (i = 1; i <= FNR; i++) { mean += data[i,j] } mean /= FNR for (i = 1; i <= FNR; i++) { variance += (data[i,j]-mean)^2 } variance /= FNR sd = sqrt(variance) printf "N %15.7g\n", FNR printf "Mean %#15.7g\n", mean printf "Variance %#15.7g\n", variance printf "S.D. %#15.7g\n", sd }
function subroutine(j, i, mean, variance, sd)以降の,{ }で囲まれた部分が関数である。( )の中には関数が呼び出されるときに値を持ってくる変数と,関数の中で使う変数を記述する。jとiの間に空白が置かれているのは,両者を区別しやすくするためである。
関数の中で使う変数は,関数の外で使われた変数と同じであっても,全く別の変数として使われる。もし,関数の中で使うとして宣言された変数以外の名前が出てくると,それは関数外で使われている変数を意味する。
したがって,以下のように書いても,同じ動作をする。
#!/usr/local/bin/gawk -f { for (j = 1; j <= 2; j++) { data[FNR,j] = $j } } END { for (j = 1; j <= 2; j++) { subroutine() } } function subroutine( i, mean, variance, sd) { mean = variance = 0 for (i = 1; i <= FNR; i++) { mean += data[i,j] } mean /= FNR for (i = 1; i <= FNR; i++) { variance += (data[i,j]-mean)^2 } variance /= FNR sd = sqrt(variance) printf "N %15.7g\n", FNR printf "Mean %#15.7g\n", mean printf "Variance %#15.7g\n", variance printf "S.D. %#15.7g\n", sd }
なお,関数に何も引き渡さない場合でも,subroutine()のように書かなくてはならない。つまり( )は省略できない。