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

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.


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

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}'

0
cat filename.txt | grep smiths | awk -F '|' '{sum+=$NF} END {print sum}'
  • -F opção para especificar o separador.
  • $NF é para "última coluna".

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}'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.