Gawk: passando matrizes para funções

10

Preso com o GNU awk 3.1.6 e acho que trabalhei em torno de seus bugs de array, 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]

imprimirá ...

global result

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

Como estou depurando, e o 3.1.6 em si já conhece bugs nesta área, estou tentando determinar onde os bugs do awk terminam e os meus começam.

Suplemento: por que o ga [] funciona dentro da função?

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

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

Suplemento: esclarecimento da resposta de Glenn Jackman

Enquanto os arrays criados fora uma função são globais para a função e podem ser passados para ela ou apenas referenciados dentro dela, arrays criados dentro de uma função permanecem locais para a função e não visível fora dela. Modificando 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 passando apenas o array x[] (na verdade, apenas um ponteiro para ele) para bar() . A matriz y[] não existe até chegarmos à função.

No entanto, se declararmos y[] incluindo-o na lista de argumentos bar() sem atribuir nada a ele fora da função, ele ficará visível depois de chamar 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 matriz y[] fora da função e passá-la com bar(x,y) , a atribuição split() 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
    
por DocSalvager 15.04.2013 / 11:13

2 respostas

6

Os parâmetros de 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 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) {...

em que os parâmetros após o espaço em branco são variáveis locais e não se destinam a receber um valor na invocação.

Não há motivos para que isso não funcione para arrays 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
    
por 22.06.2013 / 21:01
3

A documentação do gawk deixa claro que as matrizes são aprovadas por referência, e não há nenhuma maneira documentada em torno disso. O comportamento é o mesmo com gawk 4.0.1.

POSIX especifica esse comportamento , então eu não espero que você encontre qualquer implementação de awk que se comporta de outra forma.

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

    
por 15.04.2013 / 12:26