Shellskripte mit Aha-Effekt: Bash-Arrays
Eine weitere typische Anwendung ist das Erstellen einer Häufigkeits-Statistik. Bei jedem Auftreten eines Schlüssels wird diesmal der Wert inkrementiert und schon hat man die Häufigkeiten der Schlüssel ermittelt. Das soll anhand einer fiktiven Notenstatistik demonstriert werden. Fiktiv ist die Statistik deshalb, weil ich mir die Datendatei auch per Skript und der RANDOM
-Variablen erzeugt habe. Deshalb gibt es auch keine Normalverteilung.
Zuerst werden die Noten wieder per Schleife in den Zeilen 8 bis 11 eingelesen. Im Gegensatz zum Beispiel oben wird jedoch der Wert inkrementiert (Zeile 9). Deshalb listet die Kontrollausgabe (Zeilen 13 bis 19) diesmal auch Schlüssel und Wert auf. Womit der gewünschte Zweck eigentlich schon erfüllt wäre.
Weil aber bei der Ausgabe von Häufigkeiten gerne ein Histogramm erzeugt wird, habe ich das Skript entsprechend aufgepimpt. Zuerst wird (Zeilen 21 bis 27) das Maximum der Werte ermittelt. Dann kann nämlich die Länge der Histogramm-Balken normiert werden. Die Variable HMAX
legt die maximale Länge fest, sie ist in Zeile 4 definiert. Zusammen mit dem ermittelten Maximum MAX
kann dann die Länge des Balkens für einen bestimmten Wert nach der Formel
LEN = (Wert * HMAX) / MAX
ermittelt werden. Das wird in der Schleife über alle Schlüssel (Zeilen 29 bis 38) erledigt. Um das Histogramm zu »zeichnen« wird in der inneren Schleife (Zeilen 34 bis 36) LEN
mal ein Doppelkreuz ausgegeben. Ganz zum Schluss wird das Histrogramm nach Noten sortiert.
01: declare -A STAT 02: 03: # Max. Laenge eines Histogrammbalkens 04: HMAX=40 05: 06: # Noten einlesen 07: COUNT=0 08: while read NOTE; do 09: STAT[$NOTE]=$(( ${STAT[$NOTE]} + 1 )) 10: COUNT=$(( $COUNT + 1 )) 11: done < noten 12: 13: # Ausgabe: Note, Anzahl (unsortiert) 14: for I in ${!STAT[@]}; do 15: echo "$I ${STAT[$I]}" 16: done 17: 18: # Gesamtanzahl ausgeben 19: echo $COUNT 20: 21: # Maximalwert der Anzahlen bestimmen 22: MAX=0 23: for I in ${!STAT[@]}; do 24: if [ ${STAT[$I]} -gt $MAX ]; then 25: MAX=${STAT[$I]} 26: fi 27: done 28: 29: # Histogramm ausgeben (sortiert) 30: echo "" 31: for I in ${!STAT[@]}; do 32: echo -n "$I (${STAT[$I]}): " 33: LEN=$(( ${STAT[$I]} * $HMAX / $MAX )) 34: for K in $(seq 1 $LEN); do 35: echo -n "#" 36: done 37: echo "" 38: done | sort