51 votes

La commande la plus courte pour calculer la somme d'une colonne de sortie sur Unix?

Je suis sûr qu'il existe un moyen rapide et facile de calculer la somme d'une colonne de valeurs sur les systèmes Unix (en utilisant quelque chose comme awk ou xargs peut-être), mais en écrivant un script shell analyser les lignes ligne par ligne est la seule chose qui me vienne à l’esprit pour le moment.

Par exemple, quel est le moyen le plus simple de modifier la commande ci-dessous pour calculer et afficher le total de la colonne SEGSZ (70300)?

 ipcs -mb | head -6
IPC status from /dev/kmem as of Mon Nov 17 08:58:17 2008
T         ID     KEY        MODE        OWNER     GROUP      SEGSZ
Shared Memory:
m          0 0x411c322e --rw-rw-rw-      root      root        348
m          1 0x4e0c0002 --rw-rw-rw-      root      root      61760
m          2 0x412013f5 --rw-rw-rw-      root      root       8192
 

89voto

Johannes Schaub - litb Points 256113
 ipcs -mb | tail +4 | awk '{ sum += $7 } END { print sum }'
 

Ou sans queue:

 ipcs -mb | awk 'NR > 3 { sum += $7 } END { print sum }'
 

Utiliser awk avec bc pour obtenir des résultats arbitraires (crédits à Jouni K. ):

 ipcs -mb | awk 'NR > 3 { print $7 }' | paste -sd+ | bc
 

13voto

Peterino Points 331

Je voudrais essayer de construire une chaîne de calcul et le nourrir à bc comme suit:

  1. grep les lignes qui contiennent les numéros de
  2. sed loin tous les caractères avant (et après) le numéro de chaque ligne
  3. xargs le résultat (pour obtenir une chaîne de nombres séparés par des blancs)
  4. tr anslate les blancs à '+' caractères
  5. bon appétit bc!

ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | bc

Il semble que ce soit un peu plus long que le awk solution, mais pour tous ceux qui ne peuvent pas lire (et de comprendre) l'étrange awk code cela peut être plus facile à saisir... :-)

Si la colombie-britannique n'est pas installé, vous pouvez utiliser des doubles parenthèses à l'étape 5 ci-dessus pour calculer le résultat:

  • echo $(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) )) ou
  • SUM=$(( $(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) )) ou
  • (( SUM=$(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +) ))

L'espacement avant et après le double parenthèses sont facultatives.

5voto

user61853 Points 39

J'ai un script utilitaire qui ajoute simplement toutes les colonnes. Il est généralement assez facile de saisir celui que vous voulez dans la sortie sur une ligne. En prime, certains suffixes SI sont reconnus.

 #!/usr/bin/awk -f
# Sum up numerical values by column (white-space separated)
#
# Usage:  $0 [file ...]
#
# stern, 1999-2005

{
    for(i = 1; i <= NF; ++i) {
        scale = 1
        if ($i ~ /[kK]$/) { scale = 1000 }
        if ($i ~ /[mM]$/) { scale = 1000*1000 }
        if ($i ~ /[gG]$/) { scale = 1000*1000*1000 }
        col[i] += scale * $i;
    }
    if (NF > maxnf) maxnf = NF;
}

END {
    for(i = 1; i <= maxnf; ++i) { printf " %.10g", col[i] }
    print "";
}
 

Exemple avec un séparateur de champ personnalisé:

 $ head /etc/passwd | addcol -F:
0 0 45 39 0 0 0
 

2voto

S.Lott Points 207588

Solution Python

 #!/usr/bin/env python
text= file("the_file","r")
total= 0
for line in text:
    data = line.split()
    if data[0] in ('T', 'Shared', 'IPC'): continue
    print line
    segsize= int(data[6])
    total += segsize
print total
 

La plupart des distributions Linux ont Python.

Si vous voulez traiter stdin dans le cadre d’une pipline, utilisez

 import sys
total = 0
for line in sys.stdin:
   ...etc...
 

Si vous voulez supposer qu'il y a toujours 3 lignes d'en-tête:

 import sys
total = 0
for line in sys.stdin.readlines()[3:]:
    total += int(line.split()[6])
print total
 

Bon mot:

 import sys; print sum( [int(line.split()[6]) for line in sys.stdin.splitlines()[3:]] )
 

1voto

warren Points 12172

Vous pourriez commencer par l'exécution des données par l'intermédiaire cut - ce qui serait au moins de garniture les colonnes vers le bas.

Vous devriez alors être en mesure de tuyau en grep, de décapage-non-numériques.

Ensuite ... eh bien, je ne suis pas sûr. Il pourrait être possible de tuyau d' bc. Si non, il pourrait certainement être remis à un shell script pour ajouter chaque élément.

Si vous avez utilisé tr pour changer les retours à la ligne (\n) à des espaces ( ), et a joué que par le biais de xargs dans votre script qui boucle jusqu'à ce qu'il n'y a pas plus d'intrants, l'ajout de chacun, vous pouvez avoir une réponse.

Donc, quelque chose de semblable à la suivante:

cat <whatever> | cut -d'\t` -f7 | grep -v <appropriate-character-class> | tr '\n' ' ' | xargs script-that-adds-arguments

J'ai peut-être l' cut drapeaux légèrement mal - mais man est votre ami :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X