Como posso somar números nas linhas de um arquivo

24

Eu tenho um arquivo que se parece com isso:

1
3
4
1
4
3
1
2

Como posso encontrar o total disso (ou seja, 1 + 3 + 4 + 1 + 4 + 3 + 1 + 2 = 19)?

Tim
fonte
1
Por contexto, estou contando o número de emblemas que tenho no Ask Ubuntu da API Stack Exchange.
Tim
Comcat badges.json | grep -o '"award_count":[0-9],"rank":"gold"' | grep -o [0-9]
Tim
Embora agora eu perceba que a API tem um badge_countmétodo.
Tim
Se você está contando os emblemas da API, o idioma que você está usando para consultar a API não pode fazer isso (python, javascript)?
Braiam

Respostas:

42

bccom uma pequena ajuda pastepara obter as linhas em uma única com +o separador:

paste -sd+ file.txt | bc

Para usar a saída de grep(ou qualquer outro comando) em vez de um arquivo estático, passe o grepSTDOUT do para o STDIN de paste:

grep .... | paste -sd+ | bc

Exemplo:

% cat file.txt            
1
3
4
1
4
3
1
2

% paste -sd+ file.txt | bc
19

% grep . file.txt | paste -sd+ | bc
19

Se você precisar usá bash-lo, poderá usar uma matriz para salvar o conteúdo do arquivo e iterar sobre os elementos ou ler o arquivo linha por linha e fazer a soma de cada linha, a segunda abordagem seria mais eficiente:

$ time { nums=$(<file.txt); for i in ${nums[@]}; do (( sum+=i )); done; echo $sum ;}
19

real    0m0.002s
user    0m0.000s
sys 0m0.000s

$ time { while read i; do (( sum+=i )); done <file.txt; echo $sum ;}
19

real    0m0.000s
user    0m0.000s
sys 0m0.000s
heemail
fonte
Hmm bom. Desculpe a mudar a pergunta: eu poderia modificar este aceitar a saída grep (ou torná-la uma linha como cat file.txt | bc?
Tim
@Tim Verifique minhas edições
heemayl
Ta, isso foi simples!
Tim
2
o jeito stdin não funcionou para mim até que descobri em outra resposta que eu tinha que usar paste -sd+ -. Por favor, altere isso.
Xerus
19

Você também pode usar o awk. Para contar o número total de linhas nos arquivos * .txt que contêm a palavra "olá":

grep -ch 'hello' *.txt | awk '{n += $1}; END{print n}'

Para simplesmente somar os números em um arquivo:

awk '{n += $1}; END{print n}' file.txt
CrazyApe84
fonte
Mas se essa linha tiver o valor "4", ela não contará 4, contará. Contará 1.
Tim
Não, ele contará 4. #
CrazyApe84 9/16
Eu quero o total dos números em um arquivo. Isso faz isso?
Tim
Eu pensei que você mudou sua pergunta para a saída de grep. Eu estava fazendo algumas suposições. Vou adicionar como simplesmente somar os valores em um arquivo.
9686 CrazyApe84
2
Sim. É realmente a mesma resposta que a de heemayl, mas, em vez de colar e bc, usa awk, o que acaba dando muito mais flexibilidade. Ainda assim, sua resposta é boa e ele foi o primeiro, por isso merece seu voto!
CrazyApe84
7

Use a numsumpartir da embalagem num-utils!

(Você pode precisar sudo apt-get install num-utils)

O comando numsumfaz exatamente o que você precisa por padrão;

$ numsum file.txt 
19

Lendo os números dos testes linha por linha em stdin:

$ printf '
1 
3
4
1
4
3
1
2' | numsum
19

Ou lendo de uma linha:

$ printf '1 3 4 1 4 3 1 2' | numsum -r
19


Mais utilitários

O pacote contém alguns outros utilitários para processamento de números que merecem ser mais conhecidos:

numaverage   - find the average of the numbers, or the mode or median
numbound     - find minimum of maximum of all lines
numgrep      - to find numbers matching ranges or sets
numinterval  - roughly like the first derivative
numnormalize - normalize numbers to an interval, like 0-1
numrandom    - random numbers from ranges or sets, eg odd.  
numrange     - similar to seq
numround     - round numbers up, down or to nearest

e um comando mais geral da calculadora numprocess,
que aplica uma expressão da linha de comando aos números nas linhas de entrada.

Volker Siegel
fonte
1

Você pode usar awkum aplicativo linux nativo útil para varrer e processar arquivos com um padrão por linha. Para sua pergunta, isso produzirá o que você deseja:

awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }' file.txt

Tubos também são aceitos:

cat file.txt | awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }'
gwarah
fonte
Não há necessidade de BEGIN{}bloqueio, veja a resposta do CrazyApe84 .
terdon
É redundante para esse problema, mas eu preferi incluí-lo devido a um objetivo didático.
gwarah
Mas o que isso ensina? É redundante para todos os problemas, awknão é C, você não precisa definir uma variável antes de usá-la. Tente awk 'BEGIN{print c+=1}'.
terdon
BEGIN {}O bloco não foi projetado apenas para inicializar variáveis. Participa na especificação do projeto. Portanto, em alguns problemas, pode ser necessário.
gwarah
0

Esse é um uso bastante simples de bashscript.

SUM=0; for line in `cat file.txt`; do SUM=$((SUM + line)); done
zomfg_zombie
fonte
Isso é muito mais simples e minimalista do que o da solução atual.
Det
0

Solução Perl:

$ perl -lnae '$c+=$_;END{print $c}' input.txt                                                                            
19

O acima pode somar todos os números em vários arquivos:

$ perl -lnae '$c+=$_;END{print $c}' input.txt input2.txt                                                                 
34

Para vários arquivos fornecidos na linha de comando, onde queremos ver a soma dos números em um arquivo individual, podemos fazer o seguinte:

$ perl -lnae '$c+=$_;if(eof){printf("%d %s\n",$c,$ARGV);$c=0}' input.txt input2.txt                                      
19 input.txt
15 input2.txt
Sergiy Kolodyazhnyy
fonte
0

Simples -

awk '{total+=$1} END{print total}' file

soma os números e fornece o total.

Sufyan Ramzan
fonte
0

Uma abordagem simples é usar um recurso interno do seu shell:

SUM=0; while read N; do SUM=$((SUM+N)); done </path/to/file
echo $SUM

Isso lê seu arquivo em linha, resume e imprime o resultado.

Se você deseja usar um pipe e usar apenas a 1ª linha, funciona assim:

SUM=0
your_command | while read -r LINE; do for N in $LINE; do break; done; SUM=$((SUM+N)); done
echo $SUM

A obtenção do primeiro elemento é feita assim:

LIST="foo bar baz"
for OBJ in $LIST; do break; done
echo $OBJ

foo
Bastian Bittorf
fonte