Gawk: Übergeben von Arrays an Funktionen

9

Ich bin mit GNU awk 3.1.6 festgefahren und denke, ich habe die Array-Fehler umgangen, habe aber immer noch ein Problem mit dem Umfang in einem 600-Zeilen-awk-Programm. Sie müssen das Verständnis des Array-Bereichs in awk überprüfen, um meinen Fehler zu finden.

Angesichts dieses illustrativen awk-Codes ...

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

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

print garray[1]

wird drucken ...

global result

Da Arrays immer als Referenz an Funktionen übergeben werden, sind alle Arrays immer global. Es gibt keine Möglichkeit, ein lokales Array zu erstellen. Ist das richtig? Es konnten keine Dokumente gefunden werden, die dies ausdrücklich angeben.

Da ich debugge und 3.1.6 selbst Fehler in diesem Bereich kennt, versuche ich festzustellen, wo die Fehler von awk aufhören und meine beginnen.

Ergänzend: Warum funktioniert ga [] dann innerhalb der Funktion?

Zunächst foo(ga)ist es eigentlich nicht erforderlich, das Array an die Funktion mit zu übergeben . Greifen Sie einfach wie garray[]in der Funktion darauf zu. Es gibt jedoch keine messbaren Leistungseinbußen, und dies hilft beim Debuggen und bei der Fehlerberichterstattung.

Bei der Verwendung foo(ga), ga[]ist ein Synonym für das globale Array garray[]. Anstatt eine lokale Kopie von zu sein garray[], ist es einfach ein Zeiger auf garray[]eine Datei, ähnlich wie ein symbolischer Link ein Zeiger auf eine Datei ist, und daher kann auf dieselbe Datei (oder dasselbe Array) unter mehr als einem Namen zugegriffen werden.

Ergänzend: Klarstellung von Glenn Jackmans Antwort

Während außerhalb einer Funktion erstellte Arrays für die Funktion global sind und an diese übergeben oder nur darin referenziert werden können, bleiben innerhalb einer Funktion erstellte Arrays tatsächlich lokal für die Funktion und außerhalb der Funktion nicht sichtbar. Das Ändern von Mr. Jackmans Beispiel veranschaulicht dies ...

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: 

Beachten Sie, dass wir nur das x[]Array (eigentlich nur einen Zeiger darauf) an übergeben bar(). Das y[]Array existiert erst, wenn wir in die Funktion eintreten.

Wenn wir jedoch deklarieren, y[]indem wir es in die bar()Argumentliste aufnehmen, ohne ihm etwas außerhalb der Funktion zuzuweisen, wird es nach dem Aufruf von bar(x,y)... sichtbar.

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

Wenn wir das y[]Array außerhalb der Funktion erstellen und mit übergeben bar(x,y), ersetzt die split()Zuweisung innerhalb der Funktion die Elemente dieses Arrays ...

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
DocSalvager
quelle

Antworten:

5

Funktionsparameter sind lokal für die Funktion.

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: 

Wenn Sie weniger Werte an eine Funktion übergeben, als Parameter vorhanden sind, sind die zusätzlichen Parameter nur leer. Möglicherweise werden manchmal Funktionen wie definiert definiert

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

Dabei sind die Parameter nach dem Leerzeichen lokale Variablen und sollen beim Aufruf keinen Wert annehmen.

Kein Grund, warum dies für lokale Arrays nicht funktioniert:

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
Glenn Jackman
quelle
3

Die Gawk-Dokumentation macht deutlich, dass Arrays als Referenz übergeben werden, und es gibt keinen dokumentierten Ausweg. Das Verhalten ist das gleiche mit gawk4.0.1.

POSIX spezifiziert dieses Verhalten , daher erwarte ich nicht, dass Sie eine awkImplementierung finden, die sich anders verhält.

Wenn Sie diese Funktionalität benötigen, können Sie sie verwenden perl. perlwird mit einem Tool ( a2p) awkgeliefert, in das Skripte übersetzt werden können perl.

Stéphane Chazelas
quelle