Primeiro, o código:
#!/usr/bin/awk -f
== "NAME" { printf "%s ", }
== "PAY" { total += * }
== "END" { print total; total = 0 }
Se você chamar o script tally
, marcá-lo como executável com chmod +x tally
e estiver no diretório que o contém, poderá executá-lo no arquivo de entrada file
com:
./tally file
No texto de entrada que você mostrou, ele mostra a saída desejada:
Jane 30
John 82
Você não declarou como deseja que a saída se pareça quando houver vários nomes sem END
entre, mas suponho que você deseje produzir o primeiro nome para cada um. Considere este arquivo de entrada:
NAME Jane Doe
NAME Clark Kent
PAY 5.77 9
END
NAME John Doe
PAY 14.22 6
NAME Linda Lee Danvers
PAY .25 4
END
Isso produz esta saída:
Jane Clark 51.93
John Linda 86.32
O que faz e por quê:
No problema que você está tentando resolver, cada uma das quais deve ser conceitualmente considerada como um registro é uma "estrofe" de várias linhas, em que uma linha pode consistir em vários campos. Cada dado tem, portanto, três "coordenadas": ⟨stanza, linha, campo⟩
Mas a abstração fundamental do AWK é ⟨record, field⟩ . O AWK ainda é uma boa escolha para esse problema, mas você terá que decidir como deseja mapear a abstração natural do problema para a abstração que sua ferramenta suporta diretamente. Em seu código, parece que você pode estar tentando tratar cada sub-rotina como um único registro, já que você criou END
o separador de registro de entrada ( RS = "END"
). Isso pode ser feito para funcionar, e espero que outras respostas sejam postadas mostrando como. Mas sugiro que o awk
trate cada linha como um registro.
A razão é que já existe outra maneira de pensar sobre seus dados de entrada: como uma lista de comandos , um por linha, onde:
- Seu comando
NAME
exibe a palavra que segue. Conceitualmente, este é o primeiro nome. - Seu comando
PAY
acumula produtos em uma variáveltotal
. Especificamente, ele multiplica os dois valores que o seguem e aumentatotal
dessa quantia. - Seu comando
END
imprimetotal
, termina a linha e redefinetotal
de volta para zero.
Como funciona, linha por linha:
#!/usr/bin/awk -f
No Ubuntu, awk
está localizado em /usr/bin
e não /bin
. O -f
flag é necessário (em qualquer sistema operacional) para informar ao AWK que o próximo argumento, qual é o nome do arquivo do script próprio , deve ser interpretado como um script em vez de como o nome de um arquivo de entrada a ser processado.
Nenhuma regra BEGIN
Você poderia criar um e definir tally = 0
, mas não é necessário porque o AWK permite a aritmética em variáveis não inicializadas e as trata como zero. (Se você estivesse executando gawk --lint -f tally file
, talvez queira incluir a atribuição explicitamente para evitar um aviso de "referência a variável não inicializada"). Coloquei uma linha em branco aqui, mas não é necessário.
== "NAME" { printf "%s ", }
Quando o primeiro campo for NAME
, imprima o segundo campo como uma sequência (
%s
) seguida por um espaço.
== "PAY" { total += * }
Quando o primeiro campo for PAY
, aumente o valor de total
pelo produto do segundo e terceiro campos.
== "END" { print total; total = 0 }
Quando o primeiro campo for END
, imprima o valor de total
. A instrução print
anexa automaticamente o separador de registro de saída, que é uma nova linha , pois você não definiu ORS
caso contrário . Em seguida, defina total
de volta para zero para se preparar para a próxima estrofe (se houver).