¿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)?


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

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

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.


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 }'

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

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

0

Simple -

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

suma los números y te da el total.


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.