ユーザ定義関数 (続き)

グローバル変数とローカル変数

関数を使う場合に知っておかなければならない重要なのひとつに, 変数の有効範囲がある. ある変数がプログラムのどこからでも参照できる, あるいは使うことができる場合, これをグローバル変数と呼ぶ.

これに対して, ある変数がプログラムの特定の範囲のなかでしか参照できないとき, これをローカル変数と呼ぶ.

awk では, 変数は**基本的に全てグローバル変数**である. 変数の有効範範囲に制限はない.

scpt19_1.awk

#!/usr/local/bin/gawk -f
# scpt19_1.awk

function global(){
    x = 2 * x # x を 2 倍する
    y = 2 * y # y を 2 倍する
    return
}

BEGIN{
    x = 3
    y = 4
    print "関数の実行前"
    print "x = " x
    print "y = " y

    global()

    print "関数実行の結果"
    print "x = " x
    print "y = " y
}



scpt19_1.awk の実行結果は:

bash-3.2$ ./scpt19_1.awk
関数の実行前
x = 3
y = 4
関数実行の結果
x = 6
y = 8

BEGIN 部で代入された, x と y の値が関数の中でそれぞれ 2 倍され, BEGIN 部の中でもその変更の結果が反映されているのがわかる.

ところが, 次のように明示的に関数の引数として, x と y を渡した場合はが異なる.

scpt19_2.awk

scpt19_2.awk の実行結果は:

bash-3.2$ ./scpt19_2.awk
関数の実行前
x = 3
y = 4
関数の内部
x = 6
y = 8
関数実行の結果
x = 3
y = 4

scpt19_3.awk

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/local/bin/gawk -f
# scpt19_2.awk

function global(a, b){
    print "関数の内部"
    a = 2 * a
    b = 2 * b

    print "a = " a
    print "b = " b
    
    return
}

BEGIN{
    x = 3
    y = 4
    global(x, y)

    print "関数の実行後"
    print "x = " x
    print "y = " y
    print "a = " a
    print "b = " b
}

scpt19_3.awk の実行結果は:

bash-3.2$ ./scpt19_3.awk
関数の内部
a = 6
b = 8
関数の実行後
x = 3
y = 4
a =
b =

関数の引数としての a と b は関数の外側で使われている a と b とはまったく無関係だということがわかる.

関数の引数はローカル変数である

ローカル変数の指定の特殊な方法

関数は独立したプログラムの部品として, いろんなスクリプトから呼び出して使える. このことを考えれば, 関数の内部で用いられる変数はできるだけローカル変数にすべきだということになる.

ローカル変数に指定せずに関数内部で変数を使った場合, 関数の外部で使われている変数名と重なると思わぬ副作用を生じる. 次のスクリプトの結果を予想してください

scpt19_4.awk

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/local/bin/gawk -f
# scpt19_4.awk

function printLetters(k){
    for(i = 1; i <= k; i++){
	printf "*"
    }

    printf "\n"
    
    return
}

BEGIN{
    for(i = 1; i <= 10; i++){
	printLetters(i)
    }
}

scpt19_4.awk の実行結果は:

bash-3.2$ ./scpt19_4.awk
*
***
*****
*******
*********

となる. これは, 関数の中で使われている i の値が, 外側の (つまり BEGIN 部の) i に影響を及ぼすためである. このように, 関数の内部の変数名が外側の変数名と同じ場合には関数内部の処理が外側に副作用をもたらす.

awk の変数は基本的にすべてグローバルと見なされるからである. 同じ名前であれば同じ変数だとみなされるからである.

こういう副作用を回避するために awk では特殊なローカル変数の設定方法を採用している. すなわち, **関数の引数として記述すること**によって, 関数内部の変数を全てローカル変数にしてしまう方法である. 具体的には, 関数の引数として, 関数内部のローカル変数を列挙する. すなわち, 次のように関数を定義する.

scpt19_5.awk

#!/usr/local/bin/gawk -f
# scpt19_5.awk

function printLetters(k, i){ # i を関数の引数として書く!!
    for(i = 1; i <= k; i++){
	printf "*"
    }

    printf "\n"
    
    return
}

BEGIN{
    for(i = 1; i <= 10; i++){
	printLetters(i)
    }
}

scpt19_5.awk の実行結果は:

bash-3.2$ ./scpt19_5.awk
*
**
***
****
*****
******
*******
********
*********
**********

Table Of Contents

Previous topic

ユーザ定義関数

Next topic

Awk リファレンス