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
NAMEexibe a palavra que segue. Conceitualmente, este é o primeiro nome. - Seu comando
PAYacumula produtos em uma variáveltotal. Especificamente, ele multiplica os dois valores que o seguem e aumentatotaldessa quantia. - Seu comando
ENDimprimetotal, termina a linha e redefinetotalde 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).