In einem Array lassen sich Massendaten verwalten. Ich habe sie schon öfters erwähnt, so dass es an der Zeit ist, sie mal genauer zu erklären.

Was ist ein Array?
Ein Array ist eine Datenstruktur, in der mehrere unterschiedliche Werte abgelegt werden können.
Eine gängige Veranschaulichung ist, sich ein Array als einen Schrank mit vielen Schubladen vorzustellen, die jede einen einzelnen Wert aufnehmen können.

Der Vorteil eines Array liegt vor allem darin, dass du nicht für jeden Wert eine eigene Variable verwenden musst, so dass sich Massendaten besser verarbeiten lassen.
Array definieren
Es gibt mehrere Möglichkeiten, in der bash ein Array zu definieren. Einer ist über declare -a, damit wird der „Schrank“ (um im Bild zu bleiben sozusagen aufgebaut.
#! /usr/bin/bash
# File: declare.sh
declare -a sbc
sbc[0]="Raspberry Pi"
echo "Länge sbc: ${#sbc[@]}"
echo "sbc=${sbc[@]}"
sbc[1]="Orange Pi"
echo "Länge sbc: ${#sbc[@]}"
echo "sbc=${sbc[@]}"
sbc[2]="Banana Pi"
echo "Länge sbc: ${#sbc[@]}"
echo "sbc=${sbc[@]}"
Hier wird das Array sbc erzeugt und die einzelnen „Schubladen“ mit Werten gefüllt.

Wie du siehst, fängt der Schrank/Schubladenvergleich jetzt schon an zu hinken, da sich das Array mit jedem neuen Element selbstständig erweitert (mein Schrank macht sowas nicht 😀 Das Verhalten ähnelt damit einer Liste in Python.
Ein weiterer Unterschied zu einem realen Schrank besteht darin, dass nicht der Wert selber im Array abgelegt wird sondern ein Verweis („Pointer“) auf den Speicherbereich, der den Wert enthält.
Du kannst einem Array auch direkt beim Anlegen Werte zuweisen. Dies geschieht ähnlich wie bei anderen Variablen. Du musst dann halt nur mehrere Werte übergeben, die in der angegebenen Reihenfolge im Array verstaut werden.
a1=(0 1 2 3 4)
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")Du erkennst, die einzelnen Werte werden durch ein Leerzeichen voneinander abgegrenzt.
Zugriff aufs Array
Wir wollen natürlich die Werte im Array wieder auslesen. Dazu musst du zunächst wissen, dass der Arrayindex 0-basiert arbeitet, wie es in der Informatik üblich ist.D.h, der erste Wert im Array ist in der „Schublade“ 0 zu finden.
Zunächst wollen wir beiden Arrays von oben ausgeben.
#! /usr/bin/bash
# File: access.sh
# Array of numbers
fib=(0 1 2 3 5 8)
#Array of Strings
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")
# outputs only element 0
echo "fib=${fib}"
# output the whole array
echo "fib=${fib[@]}"
#output element by index
echo "fib[4]=${fib[4]}"
Wie bei einer einfachen Variable versuchen wir es mit echo "${fib}". Dann wird aber nur das erste Element (mit Index 0) ausgegeben. Um das komplette Array zu zeigen benutzen wir echo "fib=${fib[@]}". Der Arrayindex wird immer innerhalb von eckigen Klammern umgeben. [4] steht für das fünfte Element im Array (weil 0-basiert).Die Notation [@] referenziert immer das gesamte Array.

Das ganze sieht sehr kompliziert aus, aber mit etwas Übung gewöhnt man sich daran. Die Notation mit den eckigen Klammern unterscheidet sich kaum von anderen Programmiersprachen.
Größe eines Arrays
Sehr häufig möchte man wissen, wie viele Elemente im Array stecken. Dies geschieht mit der Notation ${#family[@]}. Hier wird wieder das gesamte Array referenziert und das vorgestellte # soll die Länge des Arrays ermitteln.
#! /usr/bin/bash
# File: length.sh
a1=(0 1 2 3 4 5)
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")
echo "Größe family: ${#family[@]}"
echo "Größe a1: ${#a1[@]}"

Ein Array durchlaufen
Eine der wichtigsten Anwendungen für die Arraylänge ist, in einer Schleife über jedes Element im Array zu laufen.
Dazu gibt es mehrere Möglichkeiten.
for Schleife
Die for Schleife benutze ich am häufigsten. Es gibt sie in zwei Varianten. Die erste ist relativ einfach anzuwenden.
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")
for name in "${family[@]}"
do
echo "for: name=${name}"
doneHier wird automatisch jedes Element im Array nacheinander durchlaufen. Das aktuelle Element wird in der Variable ${name} abgelegt.
Die zweite Variante ist mehr der Syntax aus der Programmiersprache C angelehnt. Sie arbeitet mit einem Schleifenzähler i, und prüft bei jedem Durchlauf, ob dieser kleiner als die Länge des Array ist i < len, mit i++ wird der Zähler um eins erhöht. Der Zugriff auf das aktuelle Arrayelement geschieht über den Index ${family[i]}
len=${#family[@]}
for ((i=0;i < len; i++));do
echo "for-i: name=${family[i]},i= ${i}"
doneIch benutze diese Variante nur selten, weil es mir zu lästig ist, die Länge des Array zu ermitteln.
while Schleife
Auch die while Schleife arbeitet mit einem Schleifenzähler counter. Dieser muss vor der Schleife explizit deklariert und auf den Startwert gesetzt werden. Im Schleifenkopf wird mit ${counter} -lt ${len} geprüft, ob der Zähler noch im zulässigen Bereich liegt. Das Hochzählen geschieht am Ende des Schleifenblocks über ((counter++))
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")
len=${#family[@]}
counter=0
while [ ${counter} -lt ${len} ]; do
echo "while: name=${family[counter]},counter=${counter}"
((counter++))
doneuntil Schleife
Die until Schleife sieht der while Schleife sehr ähnlich, hat aber einen wichtigen Unterschied in der Schleifenbedingung. Während while solange läuft, wie der Zähler kleiner als len ist, läuft until so lange bis er größer oder gleich len ist und bricht dann ab. Funktionell machen beide Schleifen das gleiche.
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")
len=${#family[@]}
counter = 0
until [ $counter -ge $len ]; do
echo "until: ${family[counter]}"
((counter++))
done Zum Testlauf habe ich alle Schleifenformen in ein Script gepackt.
#! /usr/bin/bash
#Array of Strings
family=("Marge" "Homer" "Bart" "Lisa" "Maggie")
# Einfache for Schleife
for name in "${family[@]}"
do
echo "for: name=${name}"
done
echo "---"
# C-ähnliche Schleife im Index
len=${#family[@]}
for ((i=0;i < len; i++));do
echo "for-i: name=${family[i]},i= ${i}"
done
echo "---"
# while Schleife
counter=0
while [ ${counter} -lt ${len} ]; do
echo "while: name=${family[counter]},counter=${counter}"
((counter++))
done
echo "---"
# until Schleife
counter=0
until [ $counter -ge $len ]; do
echo "until: ${family[counter]}"
((counter++))
done
Slicing
Das Slicing ermöglicht es uns, Teile des Arrays herauszuschneiden und einzeln weiter zu verwenden.
#! /usr/bin/bash
# Datei: slicing.sh
family=("Marge" "Homer" "Bart" "Lisa" "Maggie" "Abe" "Herb" "Patty" "Selma")
echo "family=${family[@]}"
parents=${family[@]:0:2}
kids=${family[@]:2:2}
echo "Eltern: ${parents[@]}"
echo "Kinder: ${kids[@]}"
Dieses Script erweitert das family Array noch um ein paar Mitglieder und definiert über Slicing zwei neue Arrays. Zum einen parents und kids. Mit ${family[@]:0:2} weisen wir parents zwei Elemente zu,von Index 0 gezählt 2 Elemente. Bei kids sind es ab Index 2, 2 Elemente. Die Tanten erhalten wir ab Index 7 mit einer Länge von 2.
Allgemein ist die Syntax ${array[@]:start:länge}
assoziative arrays
Ein assoziatives Array entspricht einem Dictionary in Python. In einem assoziativen Array kannst du also bequem Key/Value-Paare ablegen. Du greifst dann nicht mehr über den Index auf einen Wert zu sondern über einen Schlüssel. Dazu formulieren wir das family Array mal um und geben jedem Familienmitglied einen Schlüssel, der seiner Rolle innerhalb der Familie entspricht.
declare -A family
family=([father]="Homer" [mother]="Marge" [son]="Bart" [daughter]="Lisa" [baby]="Maggie")
[father]="Homer" assoziiert den Schlüssel father mit dem Wert „Homer“. Zur Veranschaulichung bemühe ich nochmal die Analogie mit den Schubladen

Du kannst jetzt auf ein Arrayelement einfach mit
echo "${family[mother]}"zugreifen, ohne dich um den Index kümmern zu müssen.
mehrdimensionale Arrays
Wenn du den Schrank um eine weitere Spalte mit Schubladen erweiterst, erhältst du ein Bild, was ein mehrdimensionales Array ist.

Damit lassen sich in einem zweidimensionalen Array hervorragend Daten aus einer Datenbanktabelle oder einer Tabellenkalkulation wie Libre Office Calc unterbringen.
Der Wermutstropfen ist allerdings, dass die bash mehrdimensionale Arrays nicht wirklich unterstützt. Während in deren Programmiersprachen die Indexierung meist in dem Syntax wie schrank[1,1] ermöglichen, müssen wir in der bash einen kleinen Trick verwenden:
Wir bauen uns aus den Indizes einen Key zusammen und verstauen unsere Daten in einem assoziativen Array.
Als Beispiel nehme ich mal meine Tabelle über die Stromaufnahme verschiedener Single Board Computer. Für jedes Board erfasse ich zwei Werte, die Aufnahme im Leerlauf und den Wert unter Last. Dadurch ergibt sich eine klassische Tabelle mit drei Spalten und n Zeilen, die bilden wir in einem mehrdimensionalen Array ab. In Spalte 0 steht der Modellname, in Spalte 1 die Stromaufnahme im idle Modus und in Spalte 2 der Volllastwert. Als WordPress Tabelle sieht das so aus:
| Orange Pi Zero 2W | 1,014W | 1,99W |
| Banana Pi BPI-F3 | 3,6W | 6,8W |
| Raspberry Pi 16GB | 2,25W | 8,0W |
| Radxa Zero | 0,938W | 1,380W |
Jetzt gieße ich das ganze in ein bash Array:
#! /usr/bin/bash
# Datei: power.sh
declare -A power
# 1. Zeile (Orange Pi Zero 2W), x-Index: 0
power[0,0]="Orange Pi Zero 2W"
power[0,1]="1,014"
power[0,2]="1,99"
# 2. Zeile (Banana Pi BPI-F3) x-Index: 1
power[1,0]="Banana Pi BPI-F3"
power[1,1]="3,6"
power[1,2]="6,8"
# 3. Zeile (Raspberry Pi 16GB), x-Index: 2
power[2,0]="Raspberry Pi 16GB"
power[2,1]="2,25"
power[2,2]="8,0"
# 4. Zeile (Radxa Zero), x-Index: 3
power[3,0]="Radxa Zero"
power[3,1]="0,938"
power[3,2]="1,380"
# 2. Spalte: Stromaufnahme Leerlauf
printf "%-25s %-10s %-10s\n" "SBC" "idle" "load"
#printf 'SBC\tload\tidle\n';
for ((x=0; x<4; x++))
do
printf "%-20s %-10s %-10s\n" "${power[${x},0]}" "${power[${x},1]}W" "${power[${x},2]}W"
done
Der Index wird für ein assoziatives Array mit z.B. [0,2] jeder SBC hat eine Zeile mit drei Werten (Name, idle, Last). Zur Ausgabe benutze ich hier printf(), um eine vernünftige Ausrichtung der Spalten zu erreichen.
Fazit
Mit Arrays kannst du Massendaten bequem ablegen, ohne diskrete Variablen für jeden Wert anlegen zu müssen. Natürlich liegt der Quellcode wieder im git-Repo