¿El comportamiento de AWK END es mantener la última línea cargada en $ 0 en la página man?

Leí otra respuesta que describe cómo usar AWK para ver la última línea de salida:

$ seq 42 | awk 'END { print }' 42 

Entonces, parece que cuando se ejecuta el bloque END la última línea se carga en $0 .

Esto me sorprendió porque la primera línea no está cargada en el bloque BEGIN :

 $ seq 42 | awk 'BEGIN { print }' #=> blank 
  • ¿Esta documentation de comportamiento está en alguna parte? (Busqué en la página del manual pero no encontré nada)

El bloque BEGIN se ejecuta antes de procesar cualquier input, por lo que $0 aún no se ha inicializado.

El bloque END no hace nada a $0 , que mantiene su último valor. En su script AWK, esa es solo la última lectura de línea, porque AWK lee toda su input línea por línea, realiza su process habitual de split de campos (asignando $0 etc.), pero nunca encuentra un bloque que coincida; pero por ejemplo

 seq 42 | awk '{ $0 = "21" } END { print }' 

salidas 21, no 42, por lo que no es el caso que "cuando se ejecuta el bloque END la última línea se carga en $0 ".

Esto no está documentado en la página de gawk(1) , pero está documentado en mawk(1) (para esa implementación de AWK obviamente):

Del mismo modo, al ingresar a las acciones END , $0 , los campos y NF tienen su valor inalterado desde el último logging.

El manual GNU AWK menciona este comportamiento :

De hecho, todos BWK awk , mawk y gawk conservan el valor de $0 para su uso en las reglas de END .

"BWK awk " es el awk Brian Kernighan, el "único verdadero awk " ; implementó este comportamiento en 2005, como se documenta en su file FIXES :

24 de abril de 2005: se modificó lib.c para que los valores de $0 y otros se conserven en el bloque END, aparentemente como lo requiere posix. gracias a havard eidnes por el informe y el código.

Ese cambio es visible en la historia de "un verdadero awk " . La última versión de BWK awk comporta de la misma manera que GNU AWK:

 $ echo three fields here | ./awk '{ $0 = "one" } END { print $0 " " NF }' one 1 $ echo three fields here | ./awk 'END { $0 = "one"; print $0 " " NF }' one 1 

Según el manual de GNU awk , no está claro qué $0 debería contener en una regla END. POSIX exige que NF "retenga [su] valor" (*) , pero no mencione $0 .

Probablemente debido a un descuido, el estándar no dice que también se conserve $0 , aunque lógicamente uno podría pensar que así debería ser. De hecho, todos BWK awk, mawk y gawk conservan el valor de $0 para su uso en las reglas de END . Tenga en count, sin embargo, que algunas otras implementaciones y muchas versiones anteriores de Unix awk no lo hacen.

En cierto sentido, encuentro este comportamiento lógico. Dejar $0 para el bloque END permite un fácil acceso al último logging, si es necesario. El primer logging es de fácil acceso con NR == 1 {...} por lo que no necesita una palabra key especial. Por otro lado, ejecutar bloques BEGIN antes de cargar el primer logging permite configurar FS o RS a time para que estén activos para el primer logging.

(* Lo que eso significa, ver comentarios).