Cuenta la suma de cada columna en un archivo


9

En un archivo con un número diferente de columnas delimitadas por espacio '', Cómo contar la suma de las columnas. Un ejemplo mostraría la necesidad:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Entonces la salida sería:

  • para la columna 1 (1 + 2 + 4 + 1) = 8
  • para la columna 2 es 11
  • para la columna 3 es 7
  • para la columna 4 es 5

Respuestas:


12

Utilizando awk

awk '{for (i=1;i<=NF;i++) sum[i]+=$i;}; END{for (i in sum) print "for column "i" is " sum[i];}' FileA
for column 1 is 8
for column 2 is 11
for column 3 is 7
for column 4 is 5

El buen uso de las matrices, aunque creo que puede quedar simplificado para simplemente suma el recuento y la impresión de inmediato
Sergiy Kolodyazhnyy

De hecho, esta es la mejor respuesta aquí.
kos

5

Úselo numsumpara esa tarea y separe el procesamiento de datos y envíe los resultados.

Instalar num-utils, necesitamosnumsum

sudo apt-get install num-utils

Y comienza con

numsum -c <your_file_name>

Ejemplo

$ cat "File A"
1 2 
2 3
4 5 6 
1 1 1 5

$ numsum -c "File A"
8 11 7 5

o con su formato deseado:

$ numsum -c "File A" | awk '{for(i=1;i<=NF;i++) {print "for column "i" is "$i}}'
for column 1 is 8
for column 2 is 11
for column 3 is 7
for column 4 is 5

desde man numsum

-c      Print out the sum of each column.

ejemplos de man numsum

EXAMPLES

   Add up the 1st, 2nd and 5th columns only.

       $ numsum -c -x 1,2,5 columns
       15 40 115

   Add up the rows of numbers of a file.

        $ numsum -r columns
        55
        60
        65
        70
        75

3
#!/bin/sh

while read a b c d; do
    col1=$((col1 + a))
    col2=$((col2 + b))
    col3=$((col3 + c))
    col4=$((col4 + d))
done < File_A

echo $col1 $col2 $col3 $col4

Probablemente puedas decir (( col1 += a )), etc. Además, echo "..."es más seguro, así comowhile IFS= read -r ...
fedorqui

@fedorqui echoes seguro para usarse de esa manera para hacer eco de números, $IFSvalores predeterminados en espacios en blanco y se espera que sean números, por lo que no es necesario lidiar con barras diagonales inversas. El único inconveniente de esta respuesta es la necesidad de conocer el número de columnas antes de la ejecución.
kos

@kos nunca se puede saber cómo puede ser un archivo de entrada. Y a pesar de que el OP menciona solo números, siempre es una buena práctica prepararse para lo peor. Consulte ¿Cómo puedo leer un archivo (flujo de datos, variable) línea por línea (y / o campo por campo)? para una magnifica explicación
fedorqui

@fedorqui Por su propia declaración, pensé que esto estaba fuera de discusión; Si desea hacer puntos suponiendo que el archivo de entrada podría contener algo más que números, se está perdiendo la parte evidente: verificar si lo que se lee es un número. Agregar cadenas y usar echo "[...]"para imprimir correctamente lo que no desea generar no tiene sentido.
kos

@kos Se puede decir, por supuesto, echo $vary while read a b c, funciona aquí. Sin embargo, se acostumbrará a escribirlo de manera débil y algún día obtendrá errores extraños mientras procesa un archivo más complejo. Entonces notarás que las variables de cotización y el uso while IFS= read -r ...fueron más seguras y dirán "¡oh, sí, fedorqui tenía razón, espero tenerlo cerca para abrazarlo y mostrar gratitud!".
fedorqui

3

A juzgar por los comentarios a su propia respuesta, solo desea la suma de una columna a la vez. Si es así, aquí hay una manera no awk de hacerlo:

cut -d' ' -f3 FileA | grep . | paste -s -d+ | bc

donde reemplazaría el 3con el número de columna que le interesa.


0

Aquí hay un enfoque de guión Perl de una línea. Esto se basa en el uso de -aflag que permite la división automática de la línea actualmente leída con -nflag en array @F. Todo lo que tenemos que hacer es iterar sobre esos elementos y agregarlos a su índice respectivo en la $summatriz, por lo que efectivamente cada elemento de la matriz es la suma de cada columna respectiva. Finalmente, imprimimos el resultado dentro del ENDbloque de código.

$ perl -lane '$j=0;foreach $i (@F){$sum[$j]+=$i; $j+=1;}; END{print join("\n",@sum)} ' input.txt                                                     
8
11
7
5

Alternativamente, aquí hay un enfoque completo de script Perl. Se basa en dividir cada línea en una matriz e iterar sobre cada elemento de esa matriz agregando cada número a su posición respectiva en la @sumsmatriz. El script imprime cada línea, luego produce un informe para cada columna. La impresión de cada línea se puede eliminar agregando #antesprintf("%s",$line);

#!/usr/bin/env perl
use strict;
use warnings;

open(my $fh,"<",$ARGV[0]); 
my $i = 0;
my @sums;

while(my $line = <$fh>) { 
    printf("%s",$line);
    my @nums = split(" ",$line);
    my $j = 0;
    foreach my $num (@nums){
        $sums[$j] += $num;
        $j += 1;
    }

}

my $k = 0;
foreach my $sum (@sums){
    printf("- column %d sum: %d\n",$k,$sum);
    $k+=1;
}

close($fh);

El uso es simple chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Por ejemplo:

$ ./sum_columns_2.pl input.txt                                                                                                                       
1 2 
2 3
4 5 6 
1 1 1 5
- column 0 sum: 8
- column 1 sum: 11
- column 2 sum: 7
- column 3 sum: 5

-2

Una solución simple:

awk '{sum += $i} END {print sum}' file

Reemplace i con el número de columna, por ejemplo column1:

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

la salida es:

8

3
Esto solo te da una columna. No estás cumpliendo con tus propias especificaciones.
Oli

No dije que quiero todos los resultados en el mismo comando. además esta respuesta sólo tiene un bucle y que sea perfecto
Maythux

Entonces, ¿por qué votar abajo?
Maythux
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.