Elaborei um exemplo usando a getline
função AWK e isso está me confundindo.
$ cat in
foo
bar
baz
$ awk '{ getline tmp; print tmp; print $0 }' in
bar
foo
bar
baz
Estou lendo a próxima linha em uma variável chamada tmp
que não muda $0
conforme confirmado pelas duas primeiras linhas de saída:
bar
foo
Isto é confirmado pela seguinte tabela retirada deA linguagem de programação AWKna página 62:
Eu sei que os NR
e FNR
embutidos representam o número de linhas lidas até agora. Acho que essa é a chave para entender o que está acontecendo, mas estou confuso sobre como a mudança NR
durante uma passagem afeta passagens futuras.
Eu esperava que as próximas duas linhas fossem:
baz
bar
porque na segunda passagem $0 == bar
e tmp == baz
.
Então eu esperava que as próximas duas linhas fossem realmente apenas uma linha:
baz
porque na terceira passagem $0 == baz
e tmp == null
.
Portanto, minha saída esperada é:
bar
foo
baz
bar
baz
Acho que entender como mudar NR
durante o loop awk é a chave para entender essa saída.
- Você pode explicar por que minha saída esperada está erradaepor que a saída real está certa?
Estou awk version 20070501
correndomacOS 10.12.1
Responder1
Acho que o que está faltando é que, na configuração NR
, getline
na verdadeconsomea linha. Então, na segunda invocação, bar
já desapareceu e $0
é baz
; getline
tenta ler outra linha e falha; e o valor de tmp
permanece inalterado (ou seja, igual a bar
).
Pode ser mais fácil entender se você verificar o valor de retorno de getline
:
awk '{ if ((getline tmp) > 0) print tmp; print $0 }' in
bar
foo
baz
Responder2
Deve ficar claro se você olhar o quadro geral, por assim dizer. Um programa awk é um loop em torno do texto do programa, que lê uma linha e depois executa o programa nesta linha. Se você ler uma linha dentro do programa, o loop ao redor não conseguirá ver esta linha: ela já foi consumida.
Por exemplo, seu programa
{ getline tmp; print tmp; print $0 }
poderia ser escrito como
BEGIN {
while (getline $0) {
getline tmp; print tmp; print $0
}
}
O BEGIN
bloco é executado uma vez no início do programa, e aqui o programa não faz mais nada — é claro que esta é uma forma altamente não-idiomática de escrever código awk.
Aqui deve ficar claro que o que acontece é:
- Leia a linha 1 até
$0
a primeiragetline
- Leia a linha 2
tmp
com a segundagetline
- Imprima
tmp
então$0
, ou seja, imprima a linha 2 e depois a linha 1 - Repita com o próximo par de linhas: imprima a linha 4, depois a linha 3, etc.
Com um número ímpar de linhas, a última linha passa getline $0
e getline tmp
falha, mas você não está verificando o status de retorno tmp
, então isso simplesmente permanece inalterado e você acaba imprimindo a penúltima linha novamente.