Handliches Parsen für Zahlen mit Einheitensuffixen?


10

Angenommen, Sie haben Daten mit Mengen in einem für Menschen lesbaren Format, z. B. die Ausgabe von du -h, und möchten diese Zahlen weiter bearbeiten. Angenommen, Sie möchten Ihre Daten durch grep leiten, um eine Summierung einer Teilmenge dieser Daten durchzuführen. Sie tun dies ad-hoc auf vielen Systemen, die Sie noch nie gesehen haben, und haben nur minimale Dienstprogramme. Sie möchten Suffix-Konvertierungen für alle Standard-10 ^ n-Suffixe.

Gibt es ein Gnu-Linux-Dienstprogramm zum Konvertieren der angehängten Zahlen in reelle Zahlen innerhalb einer Pipeline? Haben Sie eine Bash-Funktion geschrieben, um dies zu tun, oder eine Perl, die leicht zu merken ist, anstatt eine Länge von Regex-Ersetzungen oder mehrere sed-Schritte?

38M     /var/crazyface/courses/200909-90147
2.7M    /var/crazyface/courses/200909-90157
1.1M    /var/crazyface/courses/200909-90159
385M    /var/crazyface/courses/200909-90161
1.3M    /var/crazyface/courses/200909-90169
376M    /var/crazyface/courses/200907-90171
8.0K    /var/crazyface/courses/200907-90173
668K    /var/crazyface/courses/200907-90175
564M    /var/crazyface/courses/200907-90178
4.0K    /var/crazyface/courses/200907-90179

| grep 200907 | <amazing suffix conversion> | awk '{s+=$1} END {print s}'


Relevante Referenzen:


2
Sie müssen selten grep und awk verwenden. Wenn Sie awk verwenden, verwenden Sie awk. Fügen Sie einfach /200907/vor Ihrem Zeilencode hinzu, z. B.awk '/200907/{s+=$1} END {print s}'
Tony

Antworten:


13

Basierend auf meiner Antwort auf eine der Fragen, mit denen Sie verlinkt haben:

awk '{
    ex = index("KMGTPEZY", substr($1, length($1)))
    val = substr($1, 0, length($1) - 1)

    prod = val * 10^(ex * 3)

    sum += prod
}
END {print sum}'

Eine andere Methode, die verwendet wird:

sed 's/G/ * 1000 M/;s/M/ * 1000 K/;s/K/ * 1000/; s/$/ +\\/; $a0' | bc

Was ist für die zweite Methode, wenn das Suffix s ist?
Djuarez

@djuarez: Für welchen Multiplikator steht das s?
Bis auf weiteres angehalten.

Keine, nur Extrapolation auf andere Einheitsfälle.
Djuarez

@djuarez: Das macht keinen Sinn. Bei dieser Antwort handelt es sich um SI-Suffixe, nicht um allgemeine Einheiten (vielleicht Sekunden?). Um den sedBefehl in meiner Antwort zu erweitern, würden Sie Klauseln hinzufügen, um zusätzliche SI-Suffixe zu behandeln, wie ich im awkBefehl zeige . s/T/ * 1000 G;am Anfang hinzugefügt würde zum Beispiel Terabyte hinzufügen.
Bis auf weiteres angehalten.

3

Sie können dazu reguläre Perl-Ausdrücke verwenden. Zum Beispiel,

$value = 0;
if($line =~ /(\d+\.?\d*)(\D+)\s+/) {
   $amplifier = 1024 if ($2 eq 'K');
   $amplifier = 1024 * 1024 if ($2 eq 'M');
   $amplifier = 1024 * 1024 * 1024 if ($2 eq 'G');
   $value = $1 * $amplifier;
}

Dies ist ein einfaches Skript. Sie können es als Ausgangspunkt betrachten. Hoffe es wird helfen!


Dies ist in der Tat eine Möglichkeit. Ich habe auch stackoverflow.com/questions/2557649/… gefunden .
Bohnen

3

Persönlich würde ich das Flag -h überhaupt nicht verwenden. Die "von Menschen lesbare" Version rundet Zahlen ab, die beim Zurückkonvertieren erneut gerundet werden müssen, um noch weniger genau zu werden. (Zum Beispiel sind 2,7 MB 2831155,2 Bytes. Was haben Sie mit den anderen 0,8 Bytes gemacht ?!)

Andernfalls können Sie darum bitten units, MiB / GiB / KiB nur in "B" zu konvertieren, und dies wird erledigt, aber Sie müssten etwas Ähnliches tun (vorausgesetzt, Ihre Ausgabe ist mit Registerkarten versehen, andernfalls cutentsprechend).

{your output} | cut -f1 '-d{tab}' | xargs -L 1 -I {} units -1t {}iB B | awk '{s+=$1}END{printf "%d\n",s}'

Gut bemerkt, dass es einen Präzisionsverlust gibt. Das Hinzufügen der Eingabe zu Einheiten funktioniert auch .. aber ich fand unitsfehlend in meiner minimalen Distribution! Ich denke, wir würden das alle anders machen, wenn wir die volle Kontrolle über alles hätten.
Bohnen

2
VALUE=$1

for i in "g G m M k K"; do
        VALUE=${VALUE//[gG]/*1024m}
        VALUE=${VALUE//[mM]/*1024k}
        VALUE=${VALUE//[kK]/*1024}
done

[ ${VALUE//\*/} -gt 0 ] && echo VALUE=$((VALUE)) || echo "ERROR: size invalid, pls enter correct size"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.