Gawk: Przekazywanie tablic do funkcji

9

Utknąłem z GNU awk 3.1.6 i myślę, że pracowałem nad jego błędami tablicowymi, ale nadal mam coś, co wygląda jak problem z zasięgiem w 600-liniowym programie awk. Potrzebuję zweryfikować zrozumienie zakresu tablicy w awk, aby znaleźć mój błąd.

Biorąc pod uwagę ten przykładowy kod awk ...

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

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

print garray[1]

wydrukuje ...

global result

Ponieważ tablice są zawsze przekazywane do funkcji przez odwołanie, wszystkie tablice są zawsze globalne. Nie ma możliwości utworzenia lokalnej tablicy. Czy to jest poprawne? Nie udało mi się znaleźć dokumentów, które wyraźnie to mówią.

Ponieważ debuguję, a sama wersja 3.1.6 znała błędy w tym obszarze, staram się ustalić, gdzie błędy awk kończą się, a moje zaczynają.

Uzupełnienie: Dlaczego ga [] działa wtedy w funkcji?

Po pierwsze, przekazanie tablicy do funkcji za pomocą foo(ga)jest w rzeczywistości niepotrzebne. Po prostu uzyskaj do niej dostęp jak garray[]w funkcji. Nie ma jednak mierzalnego ograniczenia wydajności i pomaga w debugowaniu i raportowaniu błędów.

W użyciu foo(ga), ga[]jest synonimem globalnej tablicy garray[]. Zamiast być lokalną kopią garray[], jest po prostu wskaźnikiem do garray[], podobnie jak dowiązanie symboliczne jest wskaźnikiem do pliku, dzięki czemu można uzyskać dostęp do tego samego pliku (lub tablicy) pod więcej niż jedną nazwą.

Uzupełnienie: wyjaśnienie odpowiedzi Glenna Jackmana

Podczas gdy tablice utworzone poza funkcją są globalne dla funkcji i mogą być do niej przekazywane lub po prostu do niej odwoływane, tablice utworzone wewnątrz funkcji faktycznie pozostają lokalne dla funkcji i nie są widoczne poza nią. Modyfikacja przykładu pana Jackmana ilustruje to ...

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: 

Zauważ, że przekazujemy tylko x[]tablicę (właściwie wskaźnik do niej) do bar(). y[]Array nawet nie istnieje, dopóki mamy wewnątrz funkcji.

Jeśli jednak zadeklarujemy, dołączając y[]go do bar()listy argumentów bez przypisywania czegokolwiek poza funkcją, staje się widoczny po wywołaniu 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

Wreszcie, jeśli tworzymy y[]tablicę poza funkcją i przekazujemy ją bar(x,y), split()przypisanie wewnątrz funkcji zastępuje elementy tej tablicy ...

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
źródło

Odpowiedzi:

5

Parametry funkcji są lokalne dla funkcji.

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: 

Jeśli przekażesz mniej wartości do funkcji niż istnieją parametry, dodatkowe parametry są po prostu puste. Czasami możesz zobaczyć funkcje zdefiniowane jak

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

gdzie parametry po białych znakach są zmiennymi lokalnymi i nie są przeznaczone do przyjmowania wartości przy wywołaniu.

Nie ma powodu, dla którego nie może to działać dla lokalnych tablic:

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
źródło
3

Dokumentacja gawk wyjaśnia, że ​​tablice są przekazywane przez odniesienie i nie ma na to żadnego udokumentowanego rozwiązania. Zachowanie jest takie samo z gawk4.0.1.

POSIX określa to zachowanie , więc nie oczekuję, że znajdziesz awkimplementację, która zachowuje się inaczej.

Jeśli potrzebujesz tej funkcji, możesz jej użyć perl. perlzawiera narzędzie ( a2p) do tłumaczenia awkskryptów perl.

Stéphane Chazelas
źródło