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

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

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

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

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.


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

-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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.