このスクリプトをもう少しいじってみよう。

 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
}

 subroutine(j)が関数を呼び出すところである。( )の中には,呼び出された関数で使うための変数を指定しておく。この場合は,何番目のデータを処理するかを表す変数jを関数へ引き渡している。

 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
}

 関数の中に現れるjは関数の外側で使われていたjと同じものである。

 なお,関数に何も引き渡さない場合でも,subroutine()のように書かなくてはならない。つまり( )は省略できない。


●前へ戻る   ●次へ進む
Last modified: May 15, 2002

E-mail to Shigenobu AOKI