¿Cómo puedo sumar rápidamente todos los números en un archivo?


16

Cada línea contiene texto y números en una columna. Necesito calcular la suma de los números en cada fila. ¿Cómo puedo hacer eso? Gracias

example.log contiene:

time=31sec
time=192sec
time=18sec
time=543sec

La respuesta debería ser 784


Probé este método awk '{sum + = $ 1}; END {print sum} 'example.log pero es solo para números en línea
Jack

2
Hay casi la misma pregunta en Stack Overflow : ¿Cómo puedo sumar rápidamente todos los números en un archivo? . ¿Quizás es hora de tener duplicados entre sitios?
fedorqui

Respuestas:


18

Si es su opción de grepsoporte -o, puede intentar:

$ grep -o '[[:digit:]]*' file | paste -sd+ - | bc
784

POSIXY:

$ printf %d\\n "$(( $(tr -cs 0-9 '[\n*]' <file | paste -sd+ -) ))"
784

16

Con una versión más nueva (4.x) de GNU awk:

awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'

Con otro awkintento:

awk -F '[a-z=]*' '{s+=$2}END{print s}'

44
Necesita s+0en caso de que sesté vacío, se imprimirá en 0lugar de estar vacío.
Cuonglm

Déjame explicarte eso. - Solo hay un caso en el que spuede estar vacío; si los datos de entrada no contienen líneas (es decir, si no hay ninguna entrada ). En ese caso hay dos comportamientos posibles; 1) sin entrada => sin salida, o 2) siempre genera algo, si solo es 0. Ambas son opciones sensibles según el contexto de la aplicación. La +0opción de direccionamiento 2). Para abordar la opción 1) preferiría escribir END {if(s) print s}. - Por lo tanto, no tiene sentido asumir ninguna de las opciones (para este caso de esquina sin datos) hasta que la pregunta lo especifique.
Janis

10
awk -F= '{sum+=$2};END{print sum}'

2
Preferimos respuestas largas. ¿Puedes por favor explicar cómo funciona esto?
slm

2
@slm, esa respuesta no es más o menos detallada que las otras respuestas aquí y se explica por sí misma. También tiene la ventaja de trabajar con información comotime=1.4e5sec
Stéphane Chazelas

@ StéphaneChazelas: de acuerdo, pero este es un nuevo usuario y alentamos a los usuarios a proporcionar más que respuestas de una sola línea. Un poco de texto que explique cómo funciona sería una respuesta mucho más sólida que solo el código.
slm

44
@slm, este es un nuevo usuario con una de las mejores respuestas (desde un punto de vista técnico) y recibe dos votos negativos y un comentario negativo. No es una bienvenida muy cálida.
Stéphane Chazelas

1
@TomFenech, la sintaxis POSIX para awk requiere que esos elementos de patrón / acción estén separados por ";" o "nueva línea", por lo que puede encontrar implementaciones awk donde falla sin esto ";".
Stéphane Chazelas

7

Otro GNU awk:

awk -v RS='[0-9]+' '{n+=RT};END{print n}'

A perluno:

perl -lne'$n+=$_ for/\d+/g}{print$n'

Un POSIX:

tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc

6
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'

Impresionante respuesta, pero no es necesario sed:awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
user1717828

@ user1717828: debería usar el (más corto y más compatible!) en -F'='lugar de--field-separator =
Olivier Dulac

@OlivierDulac, raro, mis man awkúnicos -F fs--field-separator fs
regalos

@ user1717828: -F'='o -F '='hay 2 formas de hacer el -F fs(fs es "=" en su caso). Agregué las comillas simples para asegurar que fs sea visto e interpretado correctamente por awk, no el shell (útil si la fs es ';' por ejemplo)
Olivier Dulac

4

Puedes probar esto:

awk -F"[^0-9]+" '{ sum += $2 } END { print sum+0; }' file

4

Todos han publicado awkrespuestas increíbles , que me gustan mucho.

Una variación para reemplazar @cuonglm grepcon sed:

sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
  1. Las sedtiras todo excepto los números.
  2. El paste -sd+ -comando une todas las líneas como una sola línea.
  3. El bcevalúa la expresión

3

Deberías usar una calculadora.

{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null

Con sus cuatro líneas que imprime:

time=31
time=223
time=241
time=784

Y más simplemente:

tr times=c '    + p' <infile |dc

... que imprime ...

31
223
241
784

Si lo que buscas es velocidad, entonces dces lo que quieres. Tradicionalmente era bcsu compilador, y todavía lo es para muchos sistemas.


No según mis medidas : depende la cantidad de trabajo que tiene que hacer para generar la fórmula
Jackman Glenn

@glennjackman: sus medidas no incluyen dctan cerca como puedo ver. ¿De qué estás hablando?
mikeserv

Por cierto, cuando se compara el equipo antiguo con el nuevo equipo, como cuando se compara con el perlconjunto de herramientas estándar de Unix, realmente no tiene mucho sentido si utiliza herramientas GNU compiladas en una cadena de herramientas GNU. Toda la hinchazón que puede afectar negativamente el rendimiento de Perl también se encuentra en todas esas utilidades GNU compiladas por GNU. Triste pero cierto. Necesita un conjunto de herramientas real, simple y simple para juzgar con precisión la diferencia. Como, por ejemplo, un conjunto de herramientas de reliquias estáticamente vinculado a las librerías musl, de esa manera puede comparar el paradigma de una herramienta / un trabajo con el de una herramienta para gobernarlos a todos.
mikeserv

3

A través de python3,

import re
with open(file) as f:
    m = f.read()
    l = re.findall(r'\d+', m)
    print(sum(map(int, l)))

re.findalldevuelve una lista de cadenas, esto no va a funcionar
iruvar

@ 1_CR ya, lo olvido. Revíselo ahora.
Avinash Raj

Quizás sum(int(e) for e in l)sea ​​más pitónico.
Cuonglm

3

Solución de bash pura (Bash 3+):

while IFS= read -r line; do                   # While it reads a line:
    if [[ "$line" =~ [0-9]+ ]]; then      # If the line contains numbers:
        ((counter+=BASH_REMATCH[0]))          # Add the current number to counter
    fi                                    # End if.
done                                  # End loop.

echo "Total number: $counter"         # Print the number.
unset counter                         # Reset counter to 0.

Version corta:

while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0

1
Quizás también:PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile
mikeserv
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.