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.