Runden und Formatieren von Zahlen in der bash

Aus BraLUG-Wiki

Wechseln zu: Navigation, Suche

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).

'Persönliche Werkzeuge