Analyse pratique des nombres avec suffixes d'unité?

10

Supposons que vous ayez des données avec des quantités dans un format lisible par l'homme, comme la sortie de du -h, et que vous souhaitiez continuer à travailler sur ces nombres. Supposons que vous souhaitiez diriger vos données via grep pour faire la somme d'un sous-ensemble de ces données. Vous effectuez cette opération de manière ponctuelle sur de nombreux systèmes que vous n'avez jamais vus auparavant et ne disposez que d'un minimum d'utilitaires. Vous voulez des conversions de suffixes pour tous les 10 ^ n suffixes standard.

Existe-t-il un utilitaire gnu-linux pour convertir les nombres suffixés en nombres réels dans un pipeline? Avez-vous une fonction bash écrite pour faire cela, ou une perl qui pourrait être facile à retenir, au lieu d'une longueur de remplacements de regex ou de plusieurs étapes sed?

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}'


Références pertinentes:

des haricots
la source
2
Vous avez rarement besoin d'utiliser grep et awk. Si vous utilisez awk, utilisez awk. Ajoutez juste /200907/devant votre code par ligne, par exempleawk '/200907/{s+=$1} END {print s}'
Tony

Réponses:

14

Sur la base de ma réponse à l'une des questions que vous avez liées à:

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}'

Une autre méthode utilisée:

sed 's/G/ * 1000 M/;s/M/ * 1000 K/;s/K/ * 1000/; s/$/ +\\/; $a0' | bc
En pause jusqu'à nouvel ordre.
la source
pour la deuxième méthode, que faire si le suffixe est s?
djuarez
@djuarez: Quel multiplicateur représente le s?
pause jusqu'à nouvel ordre.
Aucun, juste une extrapolation sur d'autres cas unitaires.
djuarez
@djuarez: Cela n'a aucun sens. Cette réponse concerne les suffixes SI, pas les unités générales (secondes, peut-être?). Pour étendre la sedcommande dans ma réponse, vous ajouteriez des clauses pour gérer des suffixes SI supplémentaires comme je le montre dans la awkcommande. s/T/ * 1000 G;ajouté au début ajouterait des téraoctets, par exemple.
pause jusqu'à nouvel ordre.
3

Vous pouvez utiliser des expressions régulières perl pour ce faire. Par exemple,

$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;
}

Ceci est un script simple. Vous pouvez le considérer comme point de départ. J'espère que cela vous aidera!

Khaled
la source
En effet, c'est une façon. J'ai également trouvé stackoverflow.com/questions/2557649/… .
haricots
3

Personnellement, je n'utiliserais pas le drapeau -h en premier lieu. La version "lisible par l'homme" arrondit les nombres qui devront être arrondis à nouveau lors de la reconversion, devenant encore moins précis. (Par exemple, 2,7 Mo correspond à 2831155,2 octets. Qu'avez-vous fait avec l'autre 0,8ème d'octet ??!)

Sinon, vous pouvez demander unitsde convertir MiB / GiB / KiB en "B" et il s'en occupera, mais vous devrez faire quelque chose comme (en supposant que votre sortie est tabulée, sinon de cutmanière appropriée)

{your output} | cut -f1 '-d{tab}' | xargs -L 1 -I {} units -1t {}iB B | awk '{s+=$1}END{printf "%d\n",s}'
DerfK
la source
Bien noté, qu'il y a une perte de précision. Compléter l'entrée des unités fonctionne également .. mais j'ai trouvé unitsmanquant sur ma distribution minimale! Je pense que nous ferions tous différemment si nous avions le contrôle total de tout.
haricots
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"
S471
la source