Comptez la somme de chaque colonne d'un fichier


9

Dans un fichier avec un nombre différent de colonnes délimitées par un espace '', Comment compter la somme des colonnes. Un exemple montrerait la nécessité:

File A:

1 2 
2 3
4 5 6 
1 1 1 5

La sortie serait alors:

  • pour la colonne 1 (1 + 2 + 4 + 1) = 8
  • pour la colonne 2 est 11
  • pour la colonne 3 est 7
  • pour la colonne 4 est 5

Réponses:


12

En utilisant 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

Bonne utilisation des tableaux, mais je pense que cela peut être simplifié en comptant simplement la somme et en l'imprimant immédiatement
Sergiy Kolodyazhnyy

En effet, c'est la meilleure réponse ici.
kos

5

À utiliser numsumpour cette tâche et à séparer entre le traitement des données et la sortie des résultats.

Installez num-utils, nous avons besoinnumsum

sudo apt-get install num-utils

Et commencez par

numsum -c <your_file_name>

Exemple

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

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

ou avec le format souhaité:

$ 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.

exemples 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

Vous pouvez probablement dire (( col1 += a )), etc. Aussi, echo "..."est plus sûr, ainsi quewhile IFS= read -r ...
fedorqui

@fedorqui echoest sûr à utiliser de cette façon pour faire écho aux nombres, aux $IFSvaleurs par défaut dans les espaces et ceux-ci devraient être des nombres, donc il n'est pas nécessaire de traiter les contre-obliques. Le seul inconvénient de cette réponse est la nécessité de connaître le nombre de colonnes avant l'exécution.
kos

@kos, vous ne pouvez jamais savoir comment un fichier d'entrée peut être. Et malgré que le PO ne mentionne que des chiffres, il est toujours bon de se préparer au pire. Voir Comment puis-je lire un fichier (flux de données, variable) ligne par ligne (et / ou champ par champ)? pour une explication magnifique.
fedorqui

@fedorqui Selon votre propre déclaration, je pensais que c'était hors de discussion; Si vous voulez faire des remarques en supposant que le fichier d'entrée puisse contenir autre chose que des nombres, il vous manque la partie flagrante: vérifier si ce qui est lu est un nombre. Ajouter des chaînes et utiliser echo "[...]"pour imprimer correctement ce que vous ne voulez pas produire n'a aucun sens.
kos

@kos Vous pouvez bien sûr dire echo $varet while read a b ccela fonctionne ici. Cependant, vous vous habituerez à l'écrire de manière faible et un jour vous obtiendrez d'étranges erreurs lors du traitement d'un fichier plus complexe. Ensuite, vous remarquerez la citation de variables et l'utilisation while IFS= read -r ...était plus sûre et vous direz "oh ouais fedorqui avait raison, j'espère que je pourrais l'avoir autour de lui pour le serrer dans ses bras pour lui montrer sa gratitude!".
fedorqui

3

À en juger par les commentaires de votre propre réponse, vous ne voulez que la somme d'une colonne à la fois. Si c'est le cas, voici une façon non awk de le faire:

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

où vous remplaceriez le 3par le numéro de colonne qui vous intéresse.


0

Voici une approche de script Perl à une ligne. Cela repose sur l'utilisation de -aflag qui permet de diviser automatiquement la ligne actuellement lue avec -nflag en tableau @F. Tout ce que nous avons à faire est d'itérer sur ces éléments et de les ajouter à leur index respectif dans le $sumtableau, ainsi chaque élément du tableau est effectivement la somme de chaque colonne respective. Enfin, nous imprimons le résultat dans le ENDbloc de code.

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

Alternativement, voici une approche complète du script Perl. Il repose sur la division de chaque ligne en tableau et l'itération sur chaque élément de ce tableau en ajoutant chaque numéro à leur possession respective dans le @sumstableau. Le script imprime chaque ligne, puis produit un rapport pour chaque colonne. L'impression de chaque ligne peut être supprimée en ajoutant #avantprintf("%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'utilisation est simple chmod +x ./sum_columns.pl && ./sum_columns.pl input.txt. Par exemple:

$ ./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

Une solution simple:

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

Remplacez i par le numéro de colonne, par exemple column1:

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

la sortie est:

8

3
Cela ne vous donne qu'une seule colonne. Vous ne répondez pas à vos propres spécifications.
Oli

Je n'ai pas déclaré que je veux tous les résultats dans la même commande. plus cette réponse a juste besoin d'une boucle et elle sera parfaite
Maythux

Alors pourquoi voter en bas?
Maythux
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.