Come posso sommare i numeri sulle righe in un file


24

Ho un file che assomiglia a questo:

1
3
4
1
4
3
1
2

Come posso trovare il totale di questo (cioè 1 + 3 + 4 + 1 + 4 + 3 + 1 + 2 = 19)?


1
Per il contesto, sto contando il numero di badge che ho su Ask Ubuntu dall'API Stack Exchange.
Tim

Concat badges.json | grep -o '"award_count":[0-9],"rank":"gold"' | grep -o [0-9]
Tim

Anche se ora mi rendo conto che l'API ha un badge_countmetodo.
Tim

Se stai contando i badge dall'API, la lingua che stai utilizzando per interrogare l'API non può farlo (python, javascript)?
Braiam,

Risposte:


42

bccon un piccolo aiuto da pasteottenere le linee in una singola con +come separatore:

paste -sd+ file.txt | bc

Per utilizzare l'output di grep(o qualsiasi altro comando) invece di un file statico, passare lo grepSTDOUT allo STDIN di paste:

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

Esempio:

% 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 è necessario utilizzare bash, è possibile utilizzare un array per salvare il contenuto del file e quindi scorrere gli elementi oppure è possibile leggere il file riga per riga ed eseguire la somma per ogni riga, il secondo approccio sarebbe più efficiente:

$ 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

Hmm bello. Mi dispiace cambiare la domanda: posso modificare questo per accettare l'output grep (o renderlo una riga simile cat file.txt | bc?
Tim

@Tim Controlla le mie modifiche
heemayl

Ta, è stato semplice!
Tim

2
il modo stdin non ha funzionato per me fino a quando non ho scoperto in un'altra risposta che ho dovuto usare paste -sd+ -. Per favore, modificalo.
Xerus,

19

Potresti usare anche awk. Per contare il numero totale di righe nei file * .txt che contengono la parola "ciao":

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

Per sommare semplicemente i numeri in un file:

awk '{n += $1}; END{print n}' file.txt

Ma se quella linea ha il valore "4" non conterà 4, lo farà. Conterà 1.
Tim

No, conterà 4.
CrazyApe84

Voglio il totale dei numeri in un file. Questo fa questo?
Tim

Pensavo avessi cambiato la tua domanda con l'output di grep. Stavo facendo alcune ipotesi. Aggiungerò come sommare semplicemente i valori in un file.
CrazyApe84,

2
Si. È davvero la stessa risposta di heemayl, ma invece di paste e bc usa awk, che alla fine offre molta più flessibilità. Tuttavia, la sua risposta è buona ed è stato il primo, quindi merita il tuo voto!
CrazyApe84,

7

Utilizzare numsumdal pacchetto num-utils!

(Potrebbe essere necessario sudo apt-get install num-utils)

Il comando numsumfa esattamente quello che ti serve per impostazione predefinita;

$ numsum file.txt 
19

Leggere i numeri dei test riga per riga da stdin:

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

O leggendo da una riga:

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


Più utilità

Il pacchetto contiene alcune altre utilità per l'elaborazione dei numeri che meritano di essere più conosciute:

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 un comando di calcolatrice più generale numprocess,
che applica un'espressione dalla riga di comando ai numeri sulle righe di input.


1

È possibile utilizzare awkun'applicazione linux nativa utile per la scansione e l'elaborazione di file con un modello per riga. Per la tua domanda, questo produrrà quello che vuoi:

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

I tubi sono anche accettati:

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

Non è necessario un BEGIN{}blocco, vedi la risposta di CrazyApe84 .
terdon,

È ridondante a questo problema, ma ho preferito includerlo a causa di uno scopo didattico.
Gwarah,

Ma cosa insegna? È ridondante per ogni problema, awknon è C, non è necessario impostare una variabile prima di usarla. Prova awk 'BEGIN{print c+=1}'.
terdon,

BEGIN {}Il blocco non è stato progettato solo per inizializzare le variabili. Partecipa alle specifiche di progettazione. Quindi, su alcuni problemi potrebbe essere necessario.
Gwarah,

0

Questo è un uso abbastanza semplice degli bashscript.

SUM=0; for line in `cat file.txt`; do SUM=$((SUM + line)); done

Questo è molto più semplice e un set di strumenti minimalista rispetto alla soluzione attuale.
Det

0

Soluzione Perl:

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

Quanto sopra può sommare tutti i numeri su più file:

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

Per più file forniti nella riga di comando in cui vogliamo vedere la somma dei numeri in un singolo file possiamo fare questo:

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

0

Semplice -

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

somma i numeri e ti dà il totale.


0

Un approccio semplice consiste nell'utilizzare una funzionalità integrata della shell:

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

Questo legge il tuo file in modo lineare, riassume e stampa il risultato.

Se vuoi usare una pipe e usare solo la prima riga, funziona così:

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

Ottenere il primo elemento è fatto in questo modo:

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

foo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.