web-dev-qa-db-ja.com

Gawk:配列を関数に渡す

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[]_へのポインタであり、シンボリックリンクがファイルへのポインタであるため、同じファイル(または配列)にさらにアクセスできます。複数の名前。

補足:Glenn Jackmanの回答の明確化

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

_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
_
9
DocSalvager

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

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
5
glenn jackman

gawkドキュメント は、配列が参照によって渡されることを明確にしており、それを回避するための文書化された方法はありません。動作はgawk4.0.1と同じです。

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

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

3