¿Cómo funciona "getline" en AWK?

¿Cómo funciona "getline" en AWK?

He preparado un ejemplo usando la getlinefunción AWK y me confunde.

$ cat in
foo
bar
baz
$ awk '{ getline tmp; print tmp; print $0 }' in
bar
foo
bar
baz

Estoy leyendo la siguiente línea en una variable denominada tmpque no cambia $0según lo confirmado por las dos primeras líneas de resultado:

bar
foo

Esto se confirma en la siguiente tabla tomada deEl lenguaje de programación AWKen la página 62:

ingrese la descripción de la imagen aquí

Sé que las NRfunciones FNRintegradas y representan el número de líneas leídas hasta el momento. Creo que esta es la clave para entender lo que está pasando, pero estoy confundido sobre cómo cambiar NRdurante un pase afecta los pases futuros.

Esperaba que las siguientes dos líneas fueran:

baz
bar

porque en el segundo pase $0 == bary tmp == baz.

Entonces esperaba que las siguientes dos líneas fueran en realidad solo una línea:

baz

porque en el tercer pase $0 == bazy tmp == null.

Entonces mi resultado esperado es:

bar
foo
baz
bar
baz

Creo que comprender cómo cambiar NRmientras se está en el bucle awk es la clave para comprender este resultado.

  • ¿Puedes explicar por qué mi resultado esperado es incorrecto?y¿Por qué el resultado real es correcto?

estoy awk version 20070501corriendomacOS 10.12.1

Respuesta1

Creo que lo que te falta es que, al establecer NR, getlineen efectoconsumela línea. Entonces en la segunda invocación, barya se ha ido y $0está baz; getlineintenta leer otra línea y falla; y el valor de tmppermanece sin cambios (es decir, igual a bar).

Puede ser más fácil de entender si verifica el valor de retorno de getline:

awk '{ if ((getline tmp) > 0) print tmp; print $0 }' in
bar
foo
baz

Respuesta2

Debería quedar claro si se mira el panorama más amplio, por así decirlo. Un programa awk es un bucle alrededor del texto del programa, que lee una línea y luego ejecuta el programa en esa línea. Si lees una línea dentro del programa, entonces el bucle circundante no podrá ver esta línea: ya se ha consumido.

Por ejemplo, su programa

{ getline tmp; print tmp; print $0 }

podría escribirse como

BEGIN {
    while (getline $0) {
        getline tmp; print tmp; print $0
    }
}

El BEGINbloque se ejecuta una vez al comienzo del programa, y ​​aquí el programa no hace nada más; por supuesto, esta es una forma muy poco idiomática de escribir código awk.

Aquí debe quedar claro que lo que sucede es:

  • Lea la línea 1 $0con la primera.getline
  • Lea la línea 2 tmpcon la segunda.getline
  • Imprima tmpentonces $0, es decir, imprima la línea 2 y luego la línea 1.
  • Repita con el siguiente par de líneas: imprima la línea 4, luego la línea 3, etc.

Con un número impar de líneas, la última línea pasa getline $0y luego getline tmpfalla, pero no está verificando el estado de la devolución tmp, por lo que esto simplemente no cambia y termina imprimiendo la penúltima línea nuevamente.

información relacionada