Runden und Formatieren von Zahlen in der bash
Aus BraLUG-Wiki
Es bestand in einem Script der Wunsch Zahlen in ein lesbares Format umzuwandeln und auszugeben. Speziell handelte es sich um die Anzahl von Bytes, die über die Netzwerkschnittstelle gehen. Ab einer Zahl > 1000000 kann das dann schon mal leicht unübersichtlich werden.
Aus diesem Grund hier mal ein kleines Shell-Script, innerhalb dessen die Funktion my_format eine Umformatierung (und die damit eventuell notwendige Rundung) des Wertes vornimmt. Als Ausgabeformat soll ungefähr soetwas rauskommen:
- Wert < 1000: xxx
- Wert >= 10000: xxx.xK
- Wert >= 1000000: xxx.xM
- Wert >= 1000000000: xxx.xG
#!/bin/bash #******************************************************************* # my_format # Uwe Berger; 2006 # # Rundet und formatiert eine uebergebene Zahl in ein besser lesbares # Format um -> Format: xxx.x<G|M|K| > # (G=Giga, M=Mega, K=Kilo) #******************************************************************* function my_format () { # 1.Uebergabeparameter ist die Zahl zahl=$1 # Vorsatzzeichen und Teiler bestimmen if [ $zahl -gt 999999999 ] ; then t=1000000000 e=G else if [ $zahl -gt 999999 ] ; then t=1000000 e=M else if [ $zahl -gt 999 ] ; then t=1000 e=K else # gleich ausgeben, es muss nichts formatiert werden printf "%5d " $zahl return fi fi fi # Zwischenvars. zum Runden berechnen tr=`expr $t / 20`; tt=`expr $t / 10`; # Runden und ganzzahligen Teil berechnen zr=`expr $zahl + $tr` z1=`expr $zr / $t` # Rest auf eine Stelle berechnen z2=`expr $zr % $t` z2=`expr $z2 / $tt` # und ausgeben printf "%3d.%1d%s" $z1 $z2 $e return } # ... und Funktion mal testen... my_format 298 echo my_format 2980 echo my_format 29800 echo my_format 298000 echo my_format 2980000 echo my_format 29800000 echo my_format 298000000 echo my_format 2980000000 echo my_format 29800000000 echo my_format 298000000000 echo my_format 1000
Als Ergebnis erhält man:
298 3.0K 29.8K 298.0K 3.0M 29.8M 298.0M 3.0G 29.8G 298.0G 1.0K
Hier eine Version, die ohne expr
auskommt (Vorschlag von MaD) und damit auch schneller arbeitet (Ergebnisausgabe der Testbeispiele ist wie oben):
function my_format () { # 1.Uebergabeparameter ist die Zahl zahl=$1 # Vorsatzzeichen und Teiler bestimmen if [ $zahl -gt 999999999 ] ; then t=1000000000 e=G else if [ $zahl -gt 999999 ] ; then t=1000000 e=M else if [ $zahl -gt 999 ] ; then t=1000 e=K else # gleich ausgeben, es muss nichts formatiert werden printf "%5d " $zahl return fi fi fi # Runden und ganzzahligen Teil berechnen z1=$((($zahl+($t/20))/$t)) # Rest auf eine Stelle berechnen z2=$(((($zahl+($t/20))%$t)/($t/10))) # und ausgeben printf "%3d.%1d%s" $z1 $z2 $e return }
Die Mathematiker können sich ja mal die Berechnung von z1
und z2
genauer ansehen, ob da etwas zu vereinfachen wäre. Aber Vorsicht, es kann nur mit ganzen Zahlen gerechnet werden (z.B. 1/20 würde 0 ergeben...).
Als letztes "externe" Kommando wäre noch printf
zu ersetzen, wobei mir aber wichtig ist, dass die Ausgabe immer gleich formatiert ist (3 Stellen vor dem Punkt; 1 Stelle nach dem Punkt; eine Stelle für das Vorsatzzeichen).