Contar a soma de cada coluna em um arquivo

9

Em um arquivo com número diferente de colunas delimitadas por espaço '', Como contar a soma das colunas. Um exemplo mostraria a necessidade:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Então a saída seria:

  • para a coluna 1 (1 + 2 + 4 + 1) = 8
  • para a coluna 2 é 11
  • para a coluna 3 é 7
  • para a coluna 4 é 5
Maythux
fonte

Respostas:

12

Usando 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
chave de aço
fonte
Bom uso de matrizes embora eu acho que ele pode ficar simplificada para sum contagem justa e imprimi-lo imediatamente
Sergiy Kolodyazhnyy
De fato, esta é a melhor resposta aqui.
kos
5

Use numsumpara essa tarefa e separe entre processamento de dados e saída dos resultados.

Instalar num-utils, precisamosnumsum

sudo apt-get install num-utils

E comece com

numsum -c <your_file_name>

Exemplo

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

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

ou com o formato desejado:

$ 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

de man numsum

-c      Print out the sum of each column.

exemplos 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
AB
fonte
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
Florian Diesch
fonte
Você provavelmente pode dizer (( col1 += a )), etc. Além disso, echo "..."é mais seguro, bem comowhile IFS= read -r ...
fedorqui
O @fedorqui echoé seguro para ser usado dessa maneira para ecoar números, $IFSpadrões no espaço em branco e espera-se que sejam números, portanto, não há necessidade de lidar com barras invertidas. A única desvantagem desta resposta é a necessidade de saber o número de colunas antes da execução.
kos
@ kos você nunca sabe como pode ser um arquivo de entrada. E, apesar do PO mencionar apenas números, é sempre uma boa prática se preparar para o pior. Consulte Como posso ler um arquivo (fluxo de dados, variável) linha por linha (e / ou campo por campo)? para uma explicação magnífica.
fedorqui
@fedorqui Por sua própria declaração, pensei que isso estava fora de discussão; Se você deseja fazer pontos assumindo que o arquivo de entrada pode conter algo diferente de números, está faltando a parte flagrante: verificar se o que é lido é um número. Adicionar seqüências e usar echo "[...]"para imprimir corretamente o que você não deseja produzir não faz sentido.
kos
@ kos É claro que você pode dizer echo $vare while read a b cfunciona aqui. No entanto, você se acostumará a escrevê-lo de maneira fraca e um dia receberá erros estranhos ao processar um arquivo mais complexo. Então você notará as variáveis ​​de citação e o uso while IFS= read -r ...foi mais seguro e dirá "oh sim, Fedorqui estava certo, espero poder tê-lo por perto para abraçá-lo para demonstrar gratidão!".
Fedorqui
3

A julgar pelos comentários da sua própria resposta, você deseja apenas a soma de uma coluna por vez. Nesse caso, aqui está uma maneira não-awk de fazer isso:

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

onde você substitui o 3número da coluna pelo qual está interessado.

Trauma Digital
fonte
0

Aqui está uma abordagem de script Perl de uma linha. Isso depende do uso de -asinalizador, que permite a divisão automática da linha atualmente lida com o -nsinalizador na matriz @F. Tudo o que precisamos fazer é iterar sobre esses itens e adicioná-los ao respectivo índice na $summatriz, assim, efetivamente, cada item da matriz é soma para cada coluna respectiva. Finalmente, imprimimos o resultado no ENDbloco 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

Como alternativa, aqui está uma abordagem completa de script Perl. Ele depende da divisão de cada linha na matriz e da iteração sobre cada item dessa matriz, adicionando cada número à sua respectiva posse na @sumsmatriz. O script imprime cada linha e produz um relatório para cada coluna. A impressão de cada linha pode ser removida adicionando #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);

O uso é simples chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Por exemplo:

$ ./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
Sergiy Kolodyazhnyy
fonte
-2

Uma solução simples:

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

Substitua i pelo número da coluna, por exemplo, coluna1:

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

saída é:

8
Maythux
fonte
3
Isso só te dá uma coluna. Você não está atendendo às suas próprias especificações.
Oli
Não afirmei que quero todos os resultados no mesmo comando. além de esta resposta só precisa de um loop e ser perfeito
Maythux
Então, por que voto negativo?
Maythux