Gawk: pasar matrices a funciones

9

Atascado con GNU awk 3.1.6 y creo que he solucionado los errores de su matriz, pero todavía tengo lo que parece un problema de alcance en un programa awk de 600 líneas. Necesito verificar la comprensión del alcance de la matriz en awk para encontrar mi error.

Dado este código awk ilustrativo ...

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

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

print garray[1]

imprimirá ...

global result

Dado que las matrices siempre se pasan a las funciones por referencia, todas las matrices son siempre globales. No hay forma de crear una matriz local. ¿Es esto correcto? No he podido encontrar documentos que explícitamente digan eso.

Desde que estoy depurando, y 3.1.6 en sí mismo tiene errores conocidos en esta área, estoy tratando de determinar dónde dejan los errores de awk y dónde comienza el mío.

Suplementario: ¿Por qué ga [] funciona dentro de la función entonces?

En primer lugar, pasar la matriz a la función con foo(ga)es realmente innecesario. Simplemente acceda a él como garray[]dentro de la función. Sin embargo, no hay una penalización de rendimiento mensurable al hacerlo, y ayuda en la depuración y la notificación de errores.

Al usar foo(ga), ga[]es sinónimo de la matriz global garray[]. En lugar de ser una copia local de garray[], es simplemente un puntero a garray[], más bien como un enlace simbólico, es un puntero a un archivo y, por lo tanto, se puede acceder al mismo archivo (o matriz) con más de un nombre.

Suplementario: aclaración de la respuesta de Glenn Jackman

Si bien las matrices creadas fuera de una función son globales para la función y pueden pasarse a ella o simplemente referenciarse dentro de ella, las matrices creadas dentro de una función de hecho permanecen locales a la función y no son visibles fuera de ella. La modificación del ejemplo del Sr. Jackman ilustra esto ...

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: 

Tenga en cuenta que solo estamos pasando la x[]matriz (en realidad, solo un puntero) bar(). La y[]matriz ni siquiera existe hasta que entramos en la función.

Sin embargo, si declaramos y[]al incluirlo en la bar()lista de argumentos sin asignarle nada fuera de la función, se hace visible después de llamar 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, si creamos la y[]matriz fuera de la función y la pasamos bar(x,y), la split()asignación dentro de la función reemplaza los elementos de esa 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
fuente

Respuestas:

5

Los parámetros de la función son locales a la función.

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: 

Si pasa menos valores a una función que parámetros, los parámetros adicionales simplemente están vacíos. A veces puede ver funciones definidas como

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

donde los parámetros después del espacio en blanco son variables locales y no están destinados a tomar un valor en la invocación.

No hay razón por la que esto no funcione para las matrices locales

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

La documentación de gawk deja en claro que las matrices se pasan por referencia, y no hay una forma documentada de evitarlo. El comportamiento es el mismo con gawk4.0.1.

POSIX especifica ese comportamiento , por lo que no espero que encuentre ninguna awkimplementación que se comporte de otra manera.

Si necesita esa funcionalidad, puede usarla perl. perlviene con una herramienta ( a2p) para traducir awkscripts a perl.

Stéphane Chazelas
fuente