Eu tenho um arquivo como este:
paper 3
paper 6
eraser 2
pencil 9
pencil 44
pencil 1
Gostaria de resumir as linhas com um primeiro campo comum, assim:
paper 9
eraser 2
pencil 54
Existe uma linha bonita para fazer isso usando utilitários Unix padrão? Ou mesmo utilitários Unix não tão padronizados.
Responder1
Dê uma olhada nisso:
$ echo "$a"
paper 3
paper 6
eraser 2
pencil 9
pencil 44
pencil 1
$ awk '{a[$1]=a[$1]+$2}END{for (i in a) print i,a[i]}' <(echo "$a")
pencil 54
eraser 2
paper 9
Substitua <(echo "$a)
pelo seu file
:
$ awk '{a[$1]=a[$1]+$2}END{for (i in a) print i,a[i]}' file
Responder2
Com o utilitário não tão padrãoConjunto de dados GNU
$ datamash --whitespace groupby 1 sum 2 < file
paper 9
eraser 2
pencil 54
ou mais sucintamente
$ datamash -Wg 1 sum 2 < file
paper 9
eraser 2
pencil 54
Responder3
Se nos preocupamos com a ordem de impressão, podemos fazer o seguinte:
perl -lane '$h{$F[0]}+=$F[1]; $h[-1+keys%h]=$F[0]; END{print "$_ $h{$_}" for @h}'
A ideia é manter as somas acumuladas de um item específico no hash %h
e a ordem em que o item específico foi visto na @h
matriz. No final do arquivo, apenas imprimimos o hash (chave + valor), mas pegando a ordem do @h
array.
Resultado
paper 9
eraser 2
pencil 54
Responder4
Aqui está uma frase não tão fofa no awk:
awk '{ if (prev && prev != $1) { print prev, sum; sum = 0 }; sum += $2; prev = $1 } END { print prev, sum }' < file.txt
Requer que as linhas com o mesmo valor no primeiro campo sejam agrupadas. Se este não for o caso, você pode sort file.txt | awk ...
.