¿Cómo puedo sumar números en líneas en un archivo?

24

Tengo un archivo que se ve así:

1
3
4
1
4
3
1
2

¿Cómo puedo encontrar el total de esto (es decir, 1 + 3 + 4 + 1 + 4 + 3 + 1 + 2 = 19)?

Tim
fuente
1
Por contexto, cuento la cantidad de insignias que tengo en Ask Ubuntu desde la API de Stack Exchange.
Tim
Concat badges.json | grep -o '"award_count":[0-9],"rank":"gold"' | grep -o [0-9]
Tim
Aunque ahora me doy cuenta de que la API tiene un badge_countmétodo.
Tim
Si está contando las insignias de la API, ¿el idioma que está utilizando para consultar la API no puede hacer esto (python, javascript)?
Braiam

Respuestas:

42

bccon un poco de ayuda pastepara obtener las líneas en una sola con +el separador:

paste -sd+ file.txt | bc

Para usar la salida de grep(o cualquier otro comando) en lugar de un archivo estático, pase el grepSTDOUT de STDOIN al STDIN de paste:

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

Ejemplo:

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

% paste -sd+ file.txt | bc
19

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

Si debe usar bash, puede usar una matriz para guardar el contenido del archivo y luego iterar sobre los elementos o puede leer el archivo línea por línea y hacer la suma de cada línea, el segundo enfoque sería más 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
heemayl
fuente
Hmm bien. Perdón por cambiar la pregunta: ¿podría modificar esto para aceptar la salida grep (o hacer una línea como esta cat file.txt | bc?)
Tim
@Tim Comprueba mis ediciones
heemayl
Ta, eso fue simple!
Tim
2
La forma estándar no funcionó para mí hasta que descubrí en otra respuesta que tenía que usar paste -sd+ -. Por favor modifique eso.
Xerus
19

También podrías usar awk. Para contar el número total de líneas en archivos * .txt que contienen la palabra "hola":

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

Para simplemente sumar los números en un archivo:

awk '{n += $1}; END{print n}' file.txt
CrazyApe84
fuente
Pero si esa línea tiene el valor "4", no contará 4, ¿verdad? Contará 1.
Tim
No, contará 4.
CrazyApe84
Quiero el total de los números en un archivo. ¿Esto hace eso?
Tim
Pensé que cambiaste tu pregunta a la salida de grep. Estaba haciendo algunas suposiciones. Agregaré cómo simplemente sumar los valores en un archivo.
CrazyApe84
2
Sí. Realmente es la misma respuesta que heemayl's, pero en lugar de pegar y bc, usa awk, lo que finalmente da mucha más flexibilidad. Aún así, su respuesta es buena y él fue el primero, ¡así que merece su voto!
CrazyApe84
7

Uso numsumdel paquete num-utils!

(Puede que necesite sudo apt-get install num-utils)

El comando numsumhace exactamente lo que necesita por defecto;

$ numsum file.txt 
19

Lectura de los números de prueba línea por línea de stdin:

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

O leyendo desde una línea:

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


Más utilidades

El paquete contiene algunas otras utilidades para el procesamiento de números que merecen ser más conocidas:

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

y un comando de calculadora más general numprocess,
que aplica una expresión de la línea de comando a los números en las líneas de entrada.

Volker Siegel
fuente
1

Puede usar awk, una aplicación nativa de Linux útil para escanear y procesar archivos con un patrón por línea. Para su pregunta, esto producirá lo que desea:

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

Las tuberías también se aceptan:

cat file.txt | awk 'BEGIN { sum=0 } { sum+=$1 } END {print sum }'
gwarah
fuente
No hay necesidad de un BEGIN{}bloque, vea la respuesta de CrazyApe84 .
terdon
Es redundante a este problema, pero he preferido incluirlo debido a un propósito didáctico.
gwarah
¿Pero qué enseña? Es redundante para cada problema, awkno es C, no necesita establecer una variable antes de usarla. Tratar awk 'BEGIN{print c+=1}'.
terdon
BEGIN {}El bloque no fue diseñado solo para inicializar variables. Participa en las especificaciones de diseño. Entonces, en algunos problemas podría ser necesario.
gwarah
0

Este es un uso bastante simple de bashsecuencias de comandos.

SUM=0; for line in `cat file.txt`; do SUM=$((SUM + line)); done
zomfg_zombie
fuente
Esto es mucho más simple y un conjunto de herramientas minimalista que la solución actual.
Det
0

Solución Perl:

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

Lo anterior puede sumar todos los números en varios archivos:

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

Para múltiples archivos dados en la línea de comandos donde queremos ver la suma de números en un archivo individual, podemos hacer esto:

$ 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
fuente
0

Simple -

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

suma los números y te da el total.

Sufyan Ramzan
fuente
0

Un enfoque simple es usar una función incorporada de su shell:

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

Esto lee su archivo en línea, resume e imprime el resultado.

Si desea usar una tubería y solo usa la primera fila, funciona así:

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

Obtener el primer elemento se hace así:

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

foo
Bastian Bittorf
fuente