O bloco BEGIN é executado antes de qualquer entrada ser processada. Por isso, $0 ainda não foi inicializado.
O bloco END não faz nada para $0 , o que mantém seu último valor. Em seu script AWK, essa é apenas a última linha lida, porque o AWK lê toda a entrada de linha por linha, faz seu processamento de divisão de campo usual (atribuindo $0 e assim por diante), mas nunca encontra um bloco correspondente; mas por exemplo
seq 42 | awk '{ $0 = "21" } END { print }'
saídas 21, não 42, então não é o caso em que "quando o bloco END é executado, a última linha é carregada em $0 ".
Isso não está documentado na gawk(1) página de manual, mas é documentado em mawk(1) (para essa implementação do AWK, obviamente):
Similarly, on entry to the
ENDactions,$0, the fields andNFhave their value unaltered from the last record.
O manual do GNU AWK menciona esse comportamento :
In fact, all of BWK
awk,mawk, andgawkpreserve the value of$0for use inENDrules.
"BWK awk " é awk do Brian Kernighan, o “um verdadeiro awk ” ; implementou esse comportamento em 2005, conforme documentado em seu arquivo FIXES :
Apr 24, 2005: modified
lib.cso that values of$0et al are preserved in the END block, apparently as required by posix. thanks to havard eidnes for the report and code.
Essa alteração é visível no "histórico verdadeiro de awk " . A última versão do BWK awk se comporta da mesma maneira que o 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