O comportamento do AWK END é manter a última linha carregada em $ 0 na página man?

4

Eu leio outra resposta que descreve como usar AWK para visualizar a última linha de saída:

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

Portanto, parece que quando o bloco END é executado, a última linha é carregada em $0 .

Isso me surpreendeu porque a primeira linha não foi carregada no bloco BEGIN :

$ seq 42 | awk 'BEGIN { print }'
#=> blank
  • Esta documentação de comportamento está em algum lugar? (Eu procurei na página de manual mas não encontrei nada)
por mbigras 06.04.2017 / 22:57

2 respostas

9

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 END actions, $0, the fields and NF have their value unaltered from the last record.

O manual do GNU AWK menciona esse comportamento :

In fact, all of BWK awk, mawk, and gawk preserve the value of $0 for use in END rules.

"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.c so that values of $0 et 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
    
por 06.04.2017 / 23:11
4

De acordo com o manual do GNU awk , não está claro o que $0 deve conter em uma regra END. POSIX exige que NF "retenha [seu] valor" (*) , mas não menciona $0 .

Most probably due to an oversight, the standard does not say that $0 is also preserved, although logically one would think that it should be. In fact, all of BWK awk, mawk, and gawk preserve the value of $0 for use in END rules. Be aware, however, that some other implementations and many older versions of Unix awk do not.

De certa forma, acho esse comportamento lógico. Deixar $0 para o bloco END permite acesso fácil ao último registro, se necessário. O primeiro registro é fácil de acessar com NR == 1 {...} , portanto, não precisa de uma palavra-chave especial. Por outro lado, executar BEGIN blocks antes de carregar o primeiro registro permite configurar FS ou RS no tempo para que eles estejam ativos no primeiro registro.

(* Seja o que for que isso signifique, veja os comentários.)

    
por 06.04.2017 / 23:16

Tags