Gawk: Passando matrizes para funções

9

Preso com o GNU awk 3.1.6 e acho que trabalhei com seus bugs de matriz, mas ainda tenho o que parece ser um problema de escopo em um programa awk de 600 linhas. Preciso verificar a compreensão do escopo da matriz no awk para encontrar meu bug.

Dado este código awk ilustrativo ...

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

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

print garray[1]

irá imprimir ...

global result

Como as matrizes sempre são passadas para as funções por referência, todas as matrizes são sempre globais. Não há como criar uma matriz local. Isso está correto? Não foi possível encontrar documentos que digam isso explicitamente.

Desde que eu estou depurando, e o próprio 3.1.6 conhece bugs nessa área, estou tentando determinar onde os bugs do awk param e os meus começam.

Suplementar: Por que o ga [] funciona dentro da função então?

Antes de tudo, passar o array para a função com foo(ga)é realmente desnecessário. Basta acessá-lo como garray[]dentro da função. Entretanto, não há penalidade mensurável de desempenho ao fazê-lo, e isso ajuda na depuração e no relatório de erros.

Em usar foo(ga), ga[]é um sinônimo para a matriz global garray[]. Em vez de ser uma cópia local garray[], é simplesmente um ponteiro para garray[], assim como um link simbólico é um ponteiro para um arquivo e, portanto, o mesmo arquivo (ou matriz) pode ser acessado com mais de um nome.

Suplementar: Esclarecimento da resposta de Glenn Jackman

Enquanto matrizes criadas fora de uma função são globais para a função e podem ser passadas para ela ou apenas referenciadas dentro dela, matrizes criadas dentro de uma função permanecem de fato locais na função e não são visíveis fora dela. Modificar o exemplo do Sr. Jackman ilustra isso ...

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: 

Observe que estamos apenas passando o x[]array (na verdade, apenas um ponteiro para ele) para bar(). A y[]matriz nem existe até entrarmos na função.

No entanto, se declararmos y[]incluindo-o na bar()lista de argumentos sem atribuir nada a ele fora da função, ele se torna visível após a chamada 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

Finalmente, se criarmos a y[]matriz fora da função e a passarmos bar(x,y), a split()atribuição dentro da função substituirá os elementos dessa matriz ...

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
fonte

Respostas:

5

Os parâmetros da função são locais para a função.

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: 

Se você passar menos valores para uma função do que os parâmetros, os parâmetros extras estarão vazios. Às vezes, você pode ver funções definidas como

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

onde os parâmetros após o espaço em branco são variáveis ​​locais e não pretendem obter um valor na chamada.

Não há razão para que isso não funcione para matrizes locais:

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
fonte
3

A documentação do gawk deixa claro que as matrizes são passadas por referência e não há uma maneira documentada de contornar isso. O comportamento é o mesmo com gawk4.0.1.

O POSIX especifica esse comportamento , portanto, não espero que você encontre qualquer awkimplementação que se comporte de outra maneira.

Se você precisar dessa funcionalidade, poderá usar perl. perlvem com uma ferramenta ( a2p) para traduzir awkscripts para perl.

Stéphane Chazelas
fonte