Conta la somma di ogni colonna in un file


9

In un file con un numero diverso di colonne delimitate dallo spazio '', Come contare la somma delle colonne. Un esempio mostrerebbe la necessità:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

Quindi l'output sarebbe:

  • per la colonna 1 (1 + 2 + 4 + 1) = 8
  • per la colonna 2 è 11
  • per la colonna 3 è 7
  • per la colonna 4 è 5

Risposte:


12

utilizzando 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

Buon uso degli array, anche se penso che possa essere semplificato semplicemente contando la somma e stampandola subito
Sergiy Kolodyazhnyy,

In effetti questa è la migliore risposta qui.
kos

5

Utilizzare numsumper tale attività e separare tra l'elaborazione dei dati e l'output dei risultati.

Installa num-utils, abbiamo bisognonumsum

sudo apt-get install num-utils

E inizia con

numsum -c <your_file_name>

Esempio

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

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

o con il formato desiderato:

$ 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

a partire dal man numsum

-c      Print out the sum of each column.

esempi da 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

Probabilmente puoi dire (( col1 += a )), ecc. Inoltre, echo "..."è più sicuro, così comewhile IFS= read -r ...
fedorqui,

@fedorqui echoè sicuro da usare in quel modo per riecheggiare i numeri, i $IFSvalori predefiniti negli spazi bianchi e quelli che dovrebbero essere numeri, quindi non c'è bisogno di gestire le barre rovesciate. L'unico aspetto negativo di questa risposta è la necessità di conoscere il numero delle colonne prima dell'esecuzione.
kos

@kos non puoi mai sapere come può essere un file di input. E nonostante l'OP menzioni solo numeri, è sempre buona prassi prepararsi al peggio. Vedi Come posso leggere un file (flusso di dati, variabile) riga per riga (e / o campo per campo)? per una magnifica spiegazione.
fedorqui,

@fedorqui Per la tua stessa affermazione ho pensato che fosse fuori discussione; Se vuoi fare punti supponendo che il file di input possa contenere qualcosa di diverso dai numeri, ti manca la parte palese: controllare se ciò che viene letto è un numero. L'aggiunta di stringhe e l'utilizzo echo "[...]"per stampare correttamente ciò che non si desidera produrre non ha senso.
kos,

@kos Naturalmente puoi dire echo $vare while read a b c, funziona qui. Tuttavia, ti abituerai a scriverlo in modo debole e un giorno otterrai strani errori durante l'elaborazione di un file più complesso. Poi noterai che citare le variabili e usare while IFS= read -r ...era più sicuro e dirai "oh sì, fedorqui aveva ragione, spero di averlo in giro per abbracciarlo per mostrare gratitudine!".
fedorqui,

3

A giudicare dai commenti alla tua risposta, vuoi solo la somma di una colonna alla volta. In tal caso, ecco un modo non strano per farlo:

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

dove sostituiresti 3con il numero di colonna che ti interessa.


0

Ecco un approccio di script Perl con una sola riga. Ciò si basa sull'uso di -aflag che consente la divisione automatica della riga attualmente letta con -nflag in array @F. Tutto ciò che dobbiamo fare è iterare su quegli elementi e aggiungerli al loro rispettivo indice in $sumarray, quindi effettivamente ogni elemento dell'array è la somma per ogni rispettiva colonna. Infine, stampiamo il risultato all'interno del ENDblocco di codice.

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

In alternativa, ecco un approccio di script Perl completo. Si basa sulla divisione di ogni riga in array e sull'iterazione su ciascun elemento di tale array aggiungendo ogni numero alla rispettiva proprietà @sumsnell'array. Lo script stampa ogni riga, quindi produce un report per ogni colonna. La stampa di ogni riga può essere rimossa aggiungendo #primaprintf("%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);

L'utilizzo è semplice chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Per esempio:

$ ./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 soluzione semplice:

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

Sostituisci i con il numero di colonna, ad esempio colonna1:

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

l'output è:

8

3
Questo ti dà solo una colonna. Non stai soddisfando le tue specifiche.
Oli

Non ho dichiarato che voglio tutti i risultati con lo stesso comando. più questa risposta ha solo bisogno di un ciclo ed è perfetto
Maythux,

Quindi perché effettuare il downvoting?
Maythux,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.