Gawk:配列を関数に渡す


9

GNU awk 3.1.6で立ち往生し、配列のバグを回避したと思いますが、600行のawkプログラムでスコープの問題のように見えます。私のバグを見つけるには、awkの配列スコープの理解を確認する必要があります。

この実例のawkコードを考えると...

function foo(ga) {
  ga[1] = "global result"
}

garray[1] = "global"
foo(garray)

print garray[1]

印刷されます...

global result

配列は常に参照によって関数に渡されるため、すべての配列は常にグローバルです。ローカル配列を作成する方法はありません。これは正しいです?明示的に言っているドキュメントを見つけることができませんでした。

私がデバッグしているので、3.1.6自体にこの領域の既知のバグがあるため、awkのバグがどこに留まり、自分のバグがどこから始まるのかを特定しようとしています。

補足:ga []が関数内で機能するのはなぜですか?

まず、配列を関数に渡すことfoo(ga)は実際には不要です。garray[]関数内からアクセスするだけです。ただし、それを実行しても測定可能なパフォーマンスの低下はなく、デバッグとエラー報告に役立ちます。

を使用する場合foo(ga)ga[]はグローバル配列の同義語ですgarray[]。のローカルコピーでgarray[]garray[]なく、シンボリックリンクがファイルへのポインターであるように、単にへのポインターであり、同じファイル(または配列)に複数の名前でアクセスできます。

補足:グレン・ジャックマンの回答の明確化

関数の外で作成さた配列は関数に対してグローバルであり、関数に渡されるか、関数内で参照されるだけです、関数内で作成さた配列は実際には関数に対してローカルのままであり、関数の外からは見えません。ジャックマン氏の例を修正すると、これがわかります...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: 
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: 

x[]配列(実際には、その配列へのポインタ)のみをに渡していることに注意してくださいbar()y[]関数の中に入るまで、配列は存在しません。

ただし、関数の外部で何も割り当てずに引数リストにy[]含めて宣言するbar()と、呼び出し後に表示されbar(x,y)ます...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x,y)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: 
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: hello

最後に、y[]関数の外で配列を作成し、それをbar(x,y)で渡すとsplit()、関数内の割り当てにより、配列の要素が置き換えられます...

awk '
    function bar(x,y) {
      split("hello world", y)
      print "x[1] inside: " x[1]
      print "y[1] inside: " y[1]
    }
    BEGIN {
      x[1]="goodbye"
      y[1]="howdy"
      print "x[1] before: " x[1]
      print "y[1] before: " y[1]
      bar(x,y)
      print "x[1] after: " x[1]
      print "y[1] after: " y[1]
    }
'
x[1] before: goodbye
y[1] before: howdy
x[1] inside: goodbye
y[1] inside: hello
x[1] after: goodbye
y[1] after: hello

回答:


5

関数パラメーターは関数に対してローカルです。

awk '
    function foo(x,y) {y=x*x; print "y in function: "y} 
    BEGIN {foo(2); print "y out of function: " y}
'
y in function: 4
y out of function: 

パラメータよりも関数に渡す値が少ない場合、余分なパラメータは空になります。次のように定義された関数を時々見るかもしれません

function foo(a, b, c            d, e, f) {...

ここで、空白文字の後のパラメーターはローカル変数であり、呼び出し時に値を取ることを意図していません。

これがローカル配列で機能しない理由はありません:

awk '
    function bar(x) {
        split("hello world", x)
        print "in: " x[1]
    }
    BEGIN {
        x[1]="world"
        bar()
        print "out: " x[1]}
'
in: hello
out: world

3

gawkのドキュメントは、それが配列は参照渡しされていることが明らかになり、その周囲に文書化する方法はありません。動作はgawk4.0.1 と同じです。

POSIXはその動作を指定しているため、awk他の動作をする実装が見つかるとは思いません。

その機能が必要な場合は、を使用できますperlperlには、スクリプトをa2pに変換するツール()が付属しています。awkperl

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.