Einzelne Kommandos oder Listen können auf verschiedene Weisen weiter zu Gruppen zusammengefaßt werden:
Die Operatoren zur Shellprogrammierung unterscheiden sich in Rang und Assoziativität. Prinzipiell wird eine Kommandozeile von links nach rechts abgearbeitet. Die Zusammenfassung in UND- oder ODER-Listen hat gegenüber der Auflistung mit Semikolon oder & Vorrang. Die Zusammenfassung einfacher Kommandos in Pipelines hat wiederum größere Assoziativität als die Listen. Die beiden Zeilen
{ cat /etc/gettydefs || cat /etc/gettytab; }| grep 38400 cat /etc/gettydefs || cat /etc/gettytab | grep 38400unterscheiden sich syntaktisch nur in der Klammerung, die größere Assoziativität der Pipeline führt in der zweiten Zeile aber zu einer impliziten Klammerung der beiden letzten Kommandos. Die erste Zeile schreibt die erste existierende der beiden angegebenen Dateien in den Standardausgabekanal, der durch eine Pipeline dem grep-Kommando zur Auswertung übergeben wird. Die zweite Zeile schreibt entweder die Datei /etc/gettydefs auf den Bildschirm (Standardausgabe), oder sie übergibt die Datei /etc/gettytab dem grep-Kommando.
Die geschweiften Klammern trennen selbst keine Kommandos (siehe oben). Aus diesem Grund ist ein Leerzeichen zwischen der einleitenden Klammer und dem ersten Kommando der eingeschlossenen Liste notwendig. Um die Trennung zum ersten Kommando nach der abschließenden Klammer eindeutig anzugeben, ist es sinnvoll, die eingeklammerte Liste immer mit einem Semikolon abzuschließen. Im Gegensatz zur Bourne-Shell wird in dem Beispiel oben das Kommando korrekt interpretiert, wenn das Semikolon weggelassen wird, weil die der Klammer folgende Pipeline die Kommandos trennt.Im Unterschied zur Bourne-Shell wird bei der bash auch in dem Beispiel oder bei einer Ausgabeumlenkung für die komplette Klammer keine Subshell erzeugt.
cd / $ (cd /usr/bin; ls e*); ls -F egrep elvis elvprsv elvrec env ex expand bin/ etc/ lost+found/ root/ usr/ boot/ home/ mnt/ sbin/ var/ dev/ lib/ proc/ tmp/ vmlinuz $ _erzeugt eine Subshell, in der aus dem aktuellen Wurzelverzeichnis in das Verzeichnis /usr/bin gewechselt wird. Hier können beispielsweise alle Dateien angezeigt werden, deren Name mit einem `e' beginnt. Mit den schließenden Klammern wird auch die Subshell beendet. Das darauffolgende Listing findet wieder im ursprünglich aktuellen Verzeichnis statt.
[
in
Wort ]
do Liste done
Die Werte werden normalerweise nach dem Schlüsselwort in
übergeben. Dazu können mehrere Wörter angegeben werden,
die von der Shell erweitert werden (-> Seite
). Für jeden Durchlauf wird ein Token in der
Variablen Name übergeben.
Wenn der ` in Wort' Teil fehlt, wird die Liste für
jeden gesetzten Positionsparameter (-> Seite
) einmal ausgeführt.
Die interaktive Eingabe einer for-Schleife wird (wie die Eingabe jedes anderen aus mehreren Teilen bestehenden Konstrukts) von der Shell unterstützt, indem sie einen sekundären Prompt ( PS2) zur Eingabe einer Schleife über mehrere Zeilen anbietet. Dieser sekundäre Prompt wird ausgegeben, solange die Schleife nicht mit done abgeschlossen ist.
Als Status wird der Rückgabewert des letzten ausgeführten Kommandos zurückgegeben. Wenn kein Kommando ausgeführt wurde, ist der Status Null.
In dem folgenden Beispiel werden im aktuellen Verzeichnis alle Dateien mit der Endung `foo' umbenannt, so daß sie auf `bar' enden.
$ for i in *.foo; do > base=`basename $i .foo` > mv $i $base.bar > done $ _Das basename-Kommando ist auf Seite
Die bash bietet mit ihrer Parametererweiterung eine andere
schöne Methode, die Endung vom Dateinamen zu trennen: mit der
Konstruktion base=${i%.foo}
(-> Seite ). Das
spart den Aufruf eines externen Kommandos und verbessert damit
die Performance.
Wenn eine Variable innerhalb einer for-Schleife verändert wird, ist der neue Wert auch außerhalb der Schleife sichtbar. Die bash verhält sich damit POSIX-1003.2-konform. Eine Ausnahme kann für die Zählvariable erreicht werden, indem das Kommando set -l gegeben wird. In diesem Fall wird die Zählvariable nach dem letzten Durchlauf auf den Wert vor Beginn der Schleife zurückgesetzt.
Bei der interaktiven Eingabe einer while-Schleife wird so lange der sekundäre Prompt ( PS2) ausgegeben, bis die Schleife mit done abgeschlossen ist.
Der Status der while-Schleife ist gleich dem Status des letzten Kommandos des ` do-Teils' oder Null, wenn kein Kommando ausgeführt wurde.
Im folgenden Beispiel wird die while-Schleife benutzt, um die Unterverzeichnisse z. B. des Verzeichnisses /usr/local/man anzulegen.
$ declare -i zahl=1 $ while [ $zahl -lt 10 ] > do > mkdir man$zahl > mkdir cat$zahl > zahl=$[zahl+1] > done $ _Die Deklaration von zahl als Integer-Variable ist an dieser Stelle nicht notwendig, weil die Zuweisung einer Zahl und die Verwendung in arithmetischen Ausdrücken diese Interpretation implizieren.
Zur Inkrementierung der Zählvariablen wird die Arithmetische
Erweiterung benutzt, die auf Seite beschrieben
ist. Die bash erlaubt ab Version 1.13 auch die direkte
Inkrementierung einer Integer-Variablen durch den ` +='
Zuweisungsoperator in einer arithmetischen Erweiterung oder mit
dem let-Shellkommando. Beide Varianten sind in der
Standard-Bourne-Shell nicht vorgesehen.
[
elif Liste then
Liste ... ]
[
else Liste
]
fi
Mit der optionalen elif-Konstruktion können beliebig lange if- else-Ketten erzeugt werden. Wenn der ` elif Liste'-Teil des letzten elif nicht Null liefert, wird der abschließende else-Teil bearbeitet.
Wie bei den Schleifen wird auch bei der interaktiven Eingabe einer if-Anweisung der sekundäre Prompt ausgegeben, bis die Konstruktion mit einem fi abgeschlossen ist.
Der Status der gesamten if-Konstruktion ist gleich dem Status des zuletzt ausgeführten Kommandos, oder Null, wenn kein Kommando ausgeführt wurde.
Das folgende Beispiel zeigt, wie in der Initialisierungsdatei
~
/.bashrc zwischen einer Shell im xterm und den
Textbildschirmen unterschieden werden kann.
if [ $WINDOWID ]; then TERM=xterm export XDVIFONTS=/usr/TeX/lib/tex/fonts/%f.%d%p export OPENWINHOME=/usr/openwin export PAGER=/usr/X386/bin/xless else export PAGER=/usr/bin/less fiEin weiteres Beispiel zeigt, wie in einem Shellscript unterschieden werden kann, ob die aufrufende Shell interaktiv arbeitet oder nicht.
if [ "${-#*i}" = "$-" ]; then echo Die Shell arbeitet nicht interaktiv else echo Die Shell arbeitet interaktiv fiDer in diesem Beispiel benutzte Ausdruck
["${-#*i}" = "$-" ]
ist ein schönes Beispiel für die
Parametererweiterung, wie sie auf Seite ${-#*i}
wird aus
dieser Zeichenkette ein ` i' (und alle Zeichen davor)
entfernt, wenn es enthalten ist. Der umschließende test
(-> Seite Die Anführungszeichen sind in dem Beispiel notwendig, weil die Shellvariable ` -' auch leer sein kann. In diesem Fall würde sie ohne die Anführungszeichen aus der Kommandozeile entfernt, was in dem Vergleich zu einem verdeckten Syntaxfehler und einem falschen Ergebnis des Tests führen könnte.
[
Muster [
| Muster ... ]
) Liste ;; ... ]
esac
Das case Wort wird von der bash erweitert, dann wird die daraus entstandene Zeichenkette mit den Mustern verglichen und bei Übereinstimmung die Liste von Kommandos ausgeführt. In den Suchmustern können reguläre Ausdrücke wie bei der Pfadnamenerweiterung (z. B. ` *' und ` ?') verwendet werden.
Wenn ein übereinstimmendes Muster gefunden wurde, wird die case-Anweisung beendet und nicht nach weiteren Übereinstimmungen gesucht.
Der Status ist Null, wenn keine Übereinstimmung gefunden wurde. Sonst wird der Status des zuletzt ausgeführten Kommandos der Liste übergeben.
Das dem letzten Beispiel zugrunde liegende Problem kann auch mit der case-Anweisung gelöst werden. Diese Lösung ist zwar kein typisches Beispiel für eine Vielfachverzweigung, sie bietet sich aber wegen der Auswertung regulärer Ausdrücke durch case in der Praxis eher an als das oben gegebene Beispiel.
case $- in *i\*) echo hier sollte nach der Zeichenkette 'i*' echo gesucht werden. echo *****FEHLER***** in der bash-1.12.;; *i*) echo Die Shell arbeitet interaktiv.;; *) echo Die Shell arbeitet nicht interaktiv.;; esacIn der bash Version 1.12 konnte mit der case-Anweisung nicht nach regulären Ausdrücken selbst gesucht werden, die Quotierung der Wildcards wurde ignoriert. Ab Version 1.13 ist dieser Fehler behoben.
[
in Wort...;
]
do Liste done
Der in Wort-Teil wird erweitert und die so generierten Wörter als numerierte Liste (Menü) auf dem Standardfehlerkanal ausgegeben. Mit dem PS3-Prompt wird daraufhin eine Eingabe von der Tastatur gelesen. Eine leere Eingabe führt zu einer erneuten Anzeige des Menüs.
Wenn ein Wort aus der Liste durch seine Nummer bestimmt wird, führt die bash die Kommandos der do Liste aus und stellt dabei das ausgewählte Wort in der Variablen Name zur Verfügung. Wird in der Eingabezeile keine passende Zahl übergeben, ist Name leer, die Eingabezeile ist aber in der Variablen REPLY gespeichert.
Menüteil und Ausführung der Liste werden so lange wiederholt, bis die Schleife mit break oder return verlassen wird. Es ist möglich, mit CONTROL-D das Menü unmittelbar zu verlassen.
Wenn der in Wort-Teil fehlt, werden stattdessen die Positionsparameter verwendet.
[
function ]
Name
() { Liste}
Scriptfunktionen sind Teile eines Shellscripts oder einer Initialisierungsdatei für eine interaktive Shell, die komplett in der Shellumgebung gespeichert werden. Wenn ein Kommando in der Kommandozeile mit einer solchen Funktion übereinstimmt, wird die unter dem Funktionsnamen gespeicherte Liste von Kommandos ausgeführt. Es wird dazu kein neuer Prozeß erzeugt.
Im Unterschied zu alias-Synonymen können Scriptfunktionen Argumente verarbeiten. Wenn die Scriptfunktion mit Argumenten aufgerufen wird, werden diese Argumente der Funktion als Positionsparameter übergeben. Der Spezialparameter ` #' wird aktualisiert. Der Positionsparameter ` 0' bleibt allerdings unverändert.
Mit dem local-Shellkommando ist es möglich, lokale Variablen für Scriptfunktionen zu erzeugen. Normale Shellvariablen sind ``global'', sind also in der gesamten Shell uneingeschränkt sichtbar.
Wenn in einer Scriptfunktion das Shellkommando return auftaucht, wird die Funktion beendet und mit der dem Aufruf folgenden Zeile des Shellscripts oder der interaktiven Eingabe fortgesetzt. Die Positionsparameter und der Spezialparameter ` #' werden auf ihre Werte vor dem Funktionsaufruf zurückgesetzt.
Eine Liste der definierten Scriptfunktionen erhält man in einer interaktiven Shell mit der ` -f'-Option zu den Shellkommandos declare oder typeset. Die Scriptfunktionen werden nur dann an alle Untershells weitergereicht (und stehen nur dann auch in diesen Shells zur Verfügung), wenn sie mit der Shellfunktion export unter der Option ` -f' für den Export bestimmt wurden.
Scriptfunktionen können rekursiv aufgerufen werden. Es gibt keine Begrenzung für die Anzahl der rekursiven Aufrufe.