2008-11-17 8 views
43

Ich bin mir sicher, es gibt eine schnelle und einfache Möglichkeit, die Summe einer Spalte von Werten auf Unix-Systemen zu berechnen (mit etwas wie awk oder xargs vielleicht), aber das Schreiben eines Shell-Skripts, um die Zeilen Zeile für Zeile zu analysieren was mir gerade einfällt.Kürzester Befehl zum Berechnen der Summe einer Ausgabespalte unter Unix?

Zum Beispiel, was ist der einfachste Weg, den folgenden Befehl zu ändern, um die Summe für die SEGSZ-Spalte (70300) zu berechnen und anzuzeigen?

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 

Antwort

77
ipcs -mb | tail +4 | awk '{ sum += $7 } END { print sum }' 

oder ohne Schwanz:

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

Verwenden Sie awk mit bc, um beliebig lange Ergebnisse zu erhalten (Kredite an Jouni K.):

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

+1 .. entfernt mein Duplikat :-) – toolkit

+0

Danke, sehr hilfreich! Wenn ich diesen Befehl ausführe, erhalte ich folgendes Ergebnis: 6.59246e + 08. Irgendeine Möglichkeit, awk zu zwingen, den genauen Wert (anstelle der wissenschaftlichen Notation) anzuzeigen? –

+0

Andrew, es gibt eine printf-Funktion für awk: http://www.gnu.org/software/gawk/manual/gawk.html#Printf –

1

könnten Sie beginnen, indem die Daten durch cut läuft - was zumindest würde die Spalten trimmen.

Sie sollten dann in der Lage sein, das in grep, Austreib-Nicht-Numerik zu pipen.

Dann ... nun, dann bin ich mir nicht sicher. Es könnte möglich sein, das an bc zu leiten. Wenn nicht, könnte es sicher einem Shell-Skript übergeben werden, um jedes Element hinzuzufügen.

Wenn Sie verwendet tr die Zeilenumbrüche (\n) in Leerzeichen () zu ändern, und verrohrt, dass durch xargs in Ihrem Skript, das es durchlaufen, bis keine mehr Eingänge, von denen jeder Zugabe, können Sie eine Antwort haben.

Also, so etwas wie die folgenden:

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

Ich kann die cut Flaggen etwas falsch - aber man ist dein Freund :)

2

Python Lösung

#!/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 

Die meisten Linux-Distributionen haben Python.

Wenn Sie stdin als Teil eines pipline zu verarbeiten, verwenden

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

Wenn Sie davon ausgehen wollen, dass es immer 3 Kopfzeilen:

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

One-Liner:

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

Sie können es in jedem Online-Awk-Verweis nachschlagen:

ipcs | awk ' 
BEGIN { sum = 0 } 
/0x000000/ { sum = sum + $2 } 
END {print sum}' 
3

Ich habe ein Dienstprogramm Skript, das einfach addiert alle Spalten. In der Regel ist es einfach, die gewünschte Zeile aus dem einzeiligen Ausgang zu holen. Als Bonus werden einige SI-Suffixe erkannt.

#!/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 ""; 
} 

Beispiel mit benutzerdefinierter Feldseparator: oben

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

# Verwendung: $ 0 [Datei ...] <- Es gibt kein "-F" ... Können Sie die Verwendung verdeutlichen? Welche Flags werden unterstützt? –

0

Danke für den Python one-liner !. Es half mir, den Platz auf meiner Festplatte zu überprüfen. Hier ist eine gemischte Shell/Python-Einzeiler, die dies tun - zählt Speicherplatz auf dem Gerät/dev/sda in Megabyte. Es hat einige Zeit gedauert, bis ich es herausgefunden habe, also findet vielleicht auch jemand das nützlich.

df -h -B 1M | grep dev/sda | tr -s ' '| cut -d' ' -f3 |python -c "import sys; print sum([int(num) for num in sys.stdin.readlines()])" 

oder mehr Python/weniger Schale:

df -h -B 1M | python -c "import sys; print sum([int(l.split()[2]) for l in sys.stdin.readlines() if '/dev/sda' in l])" 

wieder Dank!

12

Ich würde versuchen, eine Berechnung String zu erstellen und es zu bc ernähren wie folgt:

  1. grep die Zeilen, die die Zahlen enthalten
  2. sed entfernt alle Zeichen vor (und nach) die Zahl in jeder Zeile
  3. xargs das Ergebnis (um eine Zeichenfolge von Zahlen getrennt durch Leerzeichen zu erhalten)
  4. tr anslate die Rohlinge auf '+' Zeichen
  5. guten Appetit bc!

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

wie folgt aussieht als die Lösung awk etwas länger ist, sondern für alle, die nicht lesen können (und verstehen), um die ungerade awk Code dies einfacher sein kann, zu erreichen .. . :-)

Wenn bc nicht installiert ist, können Sie doppelte Klammern in Schritt 5 oben verwenden um das Ergebnis zu berechnen:

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

Der Abstand nach und vor den doppelten Klammern ist optional.

1

Ich weiß, dass diese Frage etwas veraltet ist, aber ich kann "meine" Antwort hier nicht sehen, also entschied ich mich trotzdem zu posten.Ich würde gehen mit einer Kombination aus

  • Schwanz (die Linien erhalten Sie benötigen)
  • tr
  • Schnitt (um nur die benötigte Spalte) (auf mehrere consequitive Räume zu einem schrumpfen)
  • Paste
  • bc (jede Zeile mit einem + Zeichen verketten)

ipcs nicht (die tatsächliche Berechnung zu tun) gibt eine Ausgang auf meinem System, so werde ich es Demo nur mit df:

# df 
Filesystem  1K-blocks Used Available Use% Mounted on 
rootfs   33027952 4037420 27312812 13%/
udev    10240  0  10240 0% /dev 
tmpfs    102108  108 102000 1% /run 
/dev/xvda1  33027952 4037420 27312812 13%/
tmpfs    5120  0  5120 0% /run/lock 
tmpfs    204200  0 204200 0% /run/shm 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web1/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web2/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web3/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web4/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client2/web5/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client2/web6/log 
# df | tail -n +2 | tr -s ' ' | cut -d ' ' -f 2 | paste -s -d+ | bc 
264545284 

Ich weiß diese besondere Berechnung auf meinem System tut nicht wirklich Sinn machen, aber es zeigt das Konzept.

Alle Teile dieser Lösung wurden in den anderen Antworten gezeigt, aber nie in dieser Kombination.