He preparado un ejemplo usando la getline
funció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 tmp
que no cambia $0
segú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:
Sé que las NR
funciones FNR
integradas 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 NR
durante un pase afecta los pases futuros.
Esperaba que las siguientes dos líneas fueran:
baz
bar
porque en el segundo pase $0 == bar
y tmp == baz
.
Entonces esperaba que las siguientes dos líneas fueran en realidad solo una línea:
baz
porque en el tercer pase $0 == baz
y tmp == null
.
Entonces mi resultado esperado es:
bar
foo
baz
bar
baz
Creo que comprender cómo cambiar NR
mientras 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 20070501
corriendomacOS 10.12.1
Respuesta1
Creo que lo que te falta es que, al establecer NR
, getline
en efectoconsumela línea. Entonces en la segunda invocación, bar
ya se ha ido y $0
está baz
; getline
intenta leer otra línea y falla; y el valor de tmp
permanece 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 BEGIN
bloque 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
$0
con la primera.getline
- Lea la línea 2
tmp
con la segunda.getline
- Imprima
tmp
entonces$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 $0
y luego getline tmp
falla, 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.