Usando awk para somar os valores de uma coluna, com base nos valores de outra coluna

64

Estou tentando somar certos números em uma coluna usando awk. Gostaria de somar apenas a coluna 3 dos "ferreiros" para obter um total de 212. Posso somar a coluna inteira usando, awkmas não apenas os "ferreiros". Eu tenho:

awk 'BEGIN {FS = "|"} ; {sum+=$3} END {print sum}' filename.txt

Também estou usando massa de vidraceiro. Obrigado por qualquer ajuda.

smiths|Login|2
olivert|Login|10
denniss|Payroll|100
smiths|Time|200
smiths|Logout|10
Jake
fonte

Respostas:

82
awk -F '|' '$1 ~ /smiths/ {sum += $3} END {print sum}' inputfilename
  • O -Fsinalizador define o separador de campos; Coloquei-o entre aspas simples, porque é um caractere de shell especial.
  • Em seguida, $1 ~ /smiths/aplica o seguinte {bloco de código} apenas às linhas em que o primeiro campo corresponde à regex /smiths/.
  • O resto é o mesmo que o seu código.

Observe que, como você realmente não está usando uma regex aqui, apenas um valor específico, você pode usar com a mesma facilidade:

awk -F '|' '$1 == "smiths" {sum += $3} END {print sum}' inputfilename

Que verifica a igualdade das strings. Isso é equivalente ao uso da regex /^smiths$/, conforme mencionado em outra resposta, que inclui a ^âncora para corresponder apenas ao início da sequência (o início do campo 1) e a $âncora para corresponder apenas ao final da sequência. Não tenho certeza de como você está familiarizado com as expressões regulares. Eles são muito poderosos, mas, nesse caso, você pode usar uma verificação de igualdade de string com a mesma facilidade.

Curinga
fonte
3
A propósito, minha referência preferida do awk é grymoire.com/Unix/Awk.html . Página muito útil.
Curinga
11
Obrigado @Wildcard! Eu era capaz de agregar ordenadamente um tamanho descompactado de arquivos particulares em grande arquivo zip com base em seu conselho :) unzip -lv /appl/tmp/data.lar | grep documentlibrary | awk '{sum += $1} END {print sum/1024/1024}'
Pawel
15

Outra abordagem é usar matrizes associativas awk, mais informações aqui . Esta linha produz a saída desejada:

awk -F '|' '{a[$1] += $3} END{print a["smiths"]}' filename.txt

Como efeito colateral, a matriz armazena todos os outros valores:

awk -F '|' '{a[$1] += $3} END{for (i in a) print i, a[i]}' filename.txt

Resultado:

smiths 212
denniss 100
olivert 10
Andrey
fonte
Esta é a resposta certa
POVA
5

Muito bom até agora. Tudo que você precisa fazer é adicionar um seletor antes do bloco para adicionar a soma. Aqui, verificamos que o primeiro argumento contém apenas "ferreiros":

awk 'BEGIN {FS = "|"} ; $1 ~ /^smiths$/ {sum+=$3} END {print sum}'

Você pode reduzir um pouco isso especificando o separador de campos como uma opção. Em awkque é geralmente uma boa idéia para inicializar variáveis na linha de comando:

awk -F'|' '$1 ~ /^smiths$/ {sum+=$3} END {print sum}'
RobertL
fonte
0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F opção para especificar o separador.
  • $NF é para "última coluna".
forzagreen
fonte
11
cate grepsão desnecessários aqui.
Andrei
Por que grep é desnecessário @Andrey? O OP deseja adicionar apenas linhas "smiths". Você precisaria modificar a declaração awk, certo?
EL
11
@EL sim, a instrução awk deve ser modificada para /smiths/{...}se a chamada grep não estiver lá. Essa é uma modificação trivial, mas oferece benefícios significativos: diminui o número de processos em execução, simplifica o controle de erros e torna o código mais claro.
Andrey
0

Pessoalmente, prefiro manter a awkseção o mais simples possível e fazer o máximo que puder sem ela. A lógica de Comingled não tira proveito do poder dos pipelines Unix e, portanto, é mais difícil de entender, depurar ou modificar para casos de uso intimamente relacionados.

cat filename.txt | perl -pe 's{.*|}{}g' | awk '{sum+=$1} END {print sum}'
Sridhar Sarnobat
fonte