BEGIN e END com o comando awk

13

De acordo com o manual do awk, BEGIN e END não são usados ​​para corresponder à entrada, mas para fornecer informações de inicialização e limpeza ao script do awk. Aqui está o exemplo dado:

ls -l | \
awk 'BEGIN { print "Files found:\n" } /\<[a|x].*\.conf$/ { print $9 }'
Files found:
amd.conf
antivir.conf
xcdroast.conf
xinetd.conf

Primeiro, isso imprime uma string para saída. Em seguida, verifica a entrada para uma correspondência de padrão, onde a entrada começa com a ou x seguido por qualquer caractere uma ou várias vezes seguido pelo .conf. Para qualquer correspondência, a 9ª coluna é impressa.

O fato de sermos forçados a usar começa aqui, isso significa que o awk pode usar apenas no máximo uma função de impressão que contém BEGIN ou END? Caso contrário, por que não podemos simplesmente usar a função de impressão no início sem a palavra-chave BEGIN? Parece que o INÍCIO é supérfluo.

JohnMerlino
fonte
Simplesmente executar o comando sem o BEGIN responderia sua pergunta, mostrando que não é supérfluo e que você obteria um resultado diferente.
MSB

Respostas:

11

O BEGINnão é supérfluo. Se você não especificar BEGIN, o printseria executado para cada linha de entrada.

Citando o manual :

Uma BEGINregra é executada apenas uma vez, antes da leitura do primeiro registro de entrada. Da mesma forma, uma ENDregra é executada apenas uma vez, depois que toda a entrada é lida.

$ seq 5 | awk 'BEGIN{print "Hello"}/4/{print}'   # Hello printed once
Hello
4
$ seq 5 | awk '{print "Hello"}/4/{print}'        # Hello printed for each line of input
Hello
Hello
Hello
Hello
4
Hello
$
devnull
fonte
7

awkprocessa cada linha de entrada para as expressões fornecidas no corpo que não sejam BEGINe ENDblocos. No caso de BEGINe ENDblocos, awkprocessará as instruções apenas uma vez, antes do início do processamento da entrada e após o processamento da entrada, respectivamente. Sem o BEGINbloco, além de não ser possível imprimir informações únicas, como cabeçalhos, não seria possível inicializar com eficiência algumas das variáveis ​​exigidas pelo corpo. Além disso, para sua informação, um awkprograma pode ter múltiplos BEGINe ENDblocos.

mkc
fonte
2

awkexecuta todos os blocos apenas quando o padrão antes de corresponder. O padrão vazio (apenas bloco) corresponde a todas as linhas. BEGINe ENDsão padrões especiais que correspondem ao início e ao final do arquivo (análogo ao significado de ^e $na direção horizontal).

Se você deseja que algo seja executado antes de ler o arquivo, use BEGIN. Por exemplo, inicialização de contadores ou algo assim. ENDpoderia então coletar os resultados.

orion
fonte
0

No exemplo dado, que considero simplificado para maior clareza pedagógica, você está certo de que é supérfluo. Você pode obter os mesmos resultados sem usar BEGIN.

1 == NR            { print "Files found:\n" }
/\<[a|x].*\.conf$/ { print $9               }

produziria os mesmos resultados, já que a instrução print é restrita apenas à primeira linha de entrada.

Dito isto, os blocos BEGINe ENDsão ferramentas incrivelmente poderosas. Como outras soluções mencionaram, você pode usar o BEGINbloco para inicializar variáveis ​​ou outras rotinas que precisam ser executadas apenas uma vez, mas também podem ser usadas para executar comandos do Awk quando não houver arquivos para processar. Um exemplo simples:

BEGIN { print sqrt(12/4) }

Você pode ver um exemplo mais sério de programação no Awk sem processar nenhuma entrada aqui .

Da mesma forma, o ENDbloco é extremamente útil para realizar cálculos e resumir todas as entradas. Isso não pode ser feito (normalmente) sem a primeira leitura de todos os dados. Um exemplo simples de resumo da entrada pode ser encontrado aqui

myq
fonte