Zum Inhalt springen

Bash/Kontrollstrukturen: Unterschied zwischen den Versionen

Aus Foxwiki
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 2: Zeile 2:


== Bedingungen testen ==
== Bedingungen testen ==
Das wichtigste Kommando ist 'test', mit dem man mannigfache Bedingungen testen kann.
Das wichtigste Kommando ist 'test', mit dem man mannigfache Bedingungen testen kann
<syntaxhighlight lang="bash" highlight="1">
<syntaxhighlight lang="bash" highlight="1">
test Argument  
test Argument
</syntaxhighlight>
</syntaxhighlight>


Dieses Kommando prüft eine Bedingung und liefert 'true' (0), falls die Bedingung erfüllt ist und 'false' (1), falls die Bedingung nicht erfüllt ist. Der Fehlerwert 2 wird zurückgegeben, wenn das Argument syntaktisch falsch ist (meist durch Ersetzung hervorgerufen).
Dieses Kommando prüft eine Bedingung und liefert 'true' (0), falls die Bedingung erfüllt ist und 'false' (1), falls die Bedingung nicht erfüllt ist. Der Fehlerwert 2 wird zurückgegeben, wenn das Argument syntaktisch falsch ist (meist durch Ersetzung hervorgerufen)


Es lassen sich Dateien, Zeichenketten und Integer-Zahlen (16 Bit, bei Linux 32 Bit) überprüfen. Das Argument von Test besteht aus einer Testoption und einem Operanden, der ein Dateiname oder eine Shell-Variable (Inhalt: String oder Zahl) sein kann.
Es lassen sich Dateien, Zeichenketten und Integer-Zahlen (16 Bit, bei Linux 32 Bit) überprüfen. Das Argument von Test besteht aus einer Testoption und einem Operanden, der ein Dateiname oder eine Shell-Variable (Inhalt: String oder Zahl) sein kann


In bestimmten Fällen können auf der rechten Seite eines Vergleichs auch Strings oder Zahlen stehen - bei der Ersetzung von leeren Variablen kann es aber zu Syntaxfehlern kommen. Weiterhin lassen sich mehrere Argumente logisch verknüpfen (UND, ODER, NICHT). Beispiel:
In bestimmten Fällen können auf der rechten Seite eines Vergleichs auch Strings oder Zahlen stehen - bei der Ersetzung von leeren Variablen kann es aber zu Syntaxfehlern kommen. Weiterhin lassen sich mehrere Argumente logisch verknüpfen (UND, ODER, NICHT). Beispiel
<syntaxhighlight lang="bash" highlight="1" copy>
<syntaxhighlight lang="bash" highlight="1" copy>
test -w /etc/passwd  
test -w /etc/passwd
</syntaxhighlight>
</syntaxhighlight>


mit der Kommandoverkettung lassen sich so schon logische Entscheidungen treffen, beispielsweise:
mit der Kommandoverkettung lassen sich so schon logische Entscheidungen treffen, beispielsweise
<syntaxhighlight lang="bash" highlight="1" copy>
<syntaxhighlight lang="bash" highlight="1" copy>
test -w /etc/passwd && echo "Du bist ROOT"  
test -w /etc/passwd && echo "Du bist ROOT"
</syntaxhighlight>
</syntaxhighlight>


Normalerweise kann statt 'test' das Argument auch in eckigen Klammern gesetzt werden. Die Klammern müssen von Leerzeichen umschlossen werden:
Normalerweise kann statt 'test' das Argument auch in eckigen Klammern gesetzt werden. Die Klammern müssen von Leerzeichen umschlossen werden
<syntaxhighlight lang="bash" highlight="1" copy>
<syntaxhighlight lang="bash" highlight="1" copy>
[ -w /etc/passwd ]  
[ -w /etc/passwd ]
</syntaxhighlight>
</syntaxhighlight>


; Operationen
; Operationen
{| class="wikitable sortable big"  
{| class="wikitable sortable big"
|-  
|-
| colspan="2" | '''Dateitests '''
| colspan="2" | '''Dateitests '''
|-
|-
| | <tt>'''-b Datei '''</tt>
| | <tt>'''-b Datei '''</tt>
| | Die Datei existiert und ist ein blockorientiertes Gerät  
| | Die Datei existiert und ist ein blockorientiertes Gerät
|-
|-
| | <tt>'''-c Datei '''</tt>
| | <tt>'''-c Datei '''</tt>
| | Die Datei existiert und ist ein zeichenorientiertes Gerät  
| | Die Datei existiert und ist ein zeichenorientiertes Gerät
|-
|-
| | <tt>'''-d Datei '''</tt>
| | <tt>'''-d Datei '''</tt>
| | Die Datei existiert und ist ein Verzeichnis  
| | Die Datei existiert und ist ein Verzeichnis
|-
|-
| | <tt>'''-e Datei'''</tt>
| | <tt>'''-e Datei'''</tt>
| | Datei existiert
| | Datei existiert
|-
|-
| | <tt>'''-f Datei '''</tt>
| | <tt>'''-f Datei '''</tt>
| | Die Datei existiert und ist eine reguläre Datei  
| | Die Datei existiert und ist eine reguläre Datei
|-
|-
| | <tt>'''-g Datei '''</tt>
| | <tt>'''-g Datei '''</tt>
| | Die Datei existiert und das Gruppen-ID-Bit ist gesetzt  
| | Die Datei existiert und das Gruppen-ID-Bit ist gesetzt
|-
|-
| | <tt>'''-h Datei '''</tt>
| | <tt>'''-h Datei '''</tt>
| | Die Datei existiert und ist ein symbolischer Link  
| | Die Datei existiert und ist ein symbolischer Link
|-
|-
| | <tt>'''-k Datei '''</tt>
| | <tt>'''-k Datei '''</tt>
| | Die Datei existiert und das Sticky-Bit ist gesetzt  
| | Die Datei existiert und das Sticky-Bit ist gesetzt
|-
|-
| | <tt>'''-p Datei '''</tt>
| | <tt>'''-p Datei '''</tt>
| | Die Datei existiert und ist eine Named Pipe  
| | Die Datei existiert und ist eine Named Pipe
|-
|-
| | <tt>'''-r Datei '''</tt>
| | <tt>'''-r Datei '''</tt>
| | Die Datei existiert und ist lesbar  
| | Die Datei existiert und ist lesbar
|-
|-
| | <tt>'''-s Datei '''</tt>
| | <tt>'''-s Datei '''</tt>
| | Die Datei existiert und ist nicht leer  
| | Die Datei existiert und ist nicht leer
|-
|-
| | <tt>'''-t [n] '''</tt>
| | <tt>'''-t [n] '''</tt>
| | DATEI-Descriptor FD (Standard: Standardausgabe) ist auf Tty offen
| | DATEI-Descriptor FD (Standard: Standardausgabe) ist auf Tty offen
|-
|-
| | <tt>'''-u Datei '''</tt>
| | <tt>'''-u Datei '''</tt>
| | Die Datei existiert und das Setuid-Bit ist gesetzt  
| | Die Datei existiert und das Setuid-Bit ist gesetzt
|-
|-
| | <tt>'''-w Datei '''</tt>
| | <tt>'''-w Datei '''</tt>
| | Die Datei existiert und ist beschreibbar  
| | Die Datei existiert und ist beschreibbar
|-
|-
| | <tt>'''-x Datei '''</tt>
| | <tt>'''-x Datei '''</tt>
| | Die Datei existiert und ist ausführbar  
| | Die Datei existiert und ist ausführbar
|-
|-
| | Datei1 -nt Datei2
| | Datei1 -nt Datei2
| | Datei1 ist neuer als Datei2
| | Datei1 ist neuer als Datei2
|-
|-
| | Datei1 -ot Datei2
| | Datei1 -ot Datei2
| | Datei1 ist älter als Datei2
| | Datei1 ist älter als Datei2
|-
|-
| | Datei1 -ef Datei2
| | Datei1 -ef Datei2
| | Beide Dateien belegen dieselbe Inode auf demselben Gerät
| | Beide Dateien belegen dieselbe Inode auf demselben Gerät
|-
|-
|}
|}


'''Beispiel'''
; Beispiel
Wenn ein Verzeichnis RCS existiert
Wenn ein Verzeichnis RCS existiert
<syntaxhighlight lang="bash" highlight="1">
<syntaxhighlight lang="bash" highlight="1">
if [ -d RCS ]     Wenn ein Verzeichnis RCS existiert. . .
if [ -d RCS ] Wenn ein Verzeichnis RCS existiert
</syntaxhighlight>
</syntaxhighlight>


{| class="wikitable sortable"  
{| class="wikitable sortable"
|-  
|-
| colspan="2" | '''Bedingungen für Zeichenfolgen '''
| colspan="2" | '''Bedingungen für Zeichenfolgen '''
|-
|-
| | <tt>'''-n s1 '''</tt>
| | <tt>'''-n s1 '''</tt>
| | Die Länge der Zeichenfolge s1 ist ungleich Null  
| | Die Länge der Zeichenfolge s1 ist ungleich Null
|-
|-
| | <tt>'''-z s1 '''</tt>
| | <tt>'''-z s1 '''</tt>
| | Die Länge der Zeichenfolge s1 ist gleich Null  
| | Die Länge der Zeichenfolge s1 ist gleich Null
|-
|-
| | <tt>'''s1 = s2 '''</tt>
| | <tt>'''s1 = s2 '''</tt>
| | Die Zeichenfolgen s1 und s2 sind identisch  
| | Die Zeichenfolgen s1 und s2 sind identisch
|-
|-
| | <tt>'''s1 != s2 '''</tt>
| | <tt>'''s1 != s2 '''</tt>
| | Die Zeichenfolgen s1 und s2 sind nicht identisch  
| | Die Zeichenfolgen s1 und s2 sind nicht identisch
|-
|-
| | <tt>'''Zeichenfolge '''</tt>
| | <tt>'''Zeichenfolge '''</tt>
| | Die Zeichenfolge ist nicht Null  
| | Die Zeichenfolge ist nicht Null
|-
|-
|}
|}


'''Beispiel'''
; Beispiel
Wenn die $Antwort nicht "j" ist
Wenn dieAntwort nicht "j" ist
<syntaxhighlight lang="bash" highlight="1">
<syntaxhighlight lang="bash" highlight="1">
if [ "$Antwort" != "j" ]
if [ "$Antwort" != "j" ]
</syntaxhighlight>
</syntaxhighlight>


{| class="wikitable sortable big"  
{| class="wikitable sortable big"
|-  
|-
| colspan="2" | '''Ganzzahlvergleiche: '''
| colspan="2" | '''Ganzzahlvergleiche: '''
|-
|-
| | <tt>'''n1 -eq n2 '''</tt>
| | <tt>'''n1 -eq n2 '''</tt>
| | n1 ist gleich n2  
| | n1 ist gleich n2
|-
|-
| | <tt>'''n1 -ge n2 '''</tt>
| | <tt>'''n1 -ge n2 '''</tt>
| | n1 ist größer oder gleich n2  
| | n1 ist größer oder gleich n2
|-
|-
| | <tt>'''n1 -gt n2 '''</tt>
| | <tt>'''n1 -gt n2 '''</tt>
| | n1 ist größer als n2  
| | n1 ist größer als n2
|-
|-
| | <tt>'''n1 -le n2 '''</tt>
| | <tt>'''n1 -le n2 '''</tt>
| | n1 ist kleiner oder gleich n2  
| | n1 ist kleiner oder gleich n2
|-
|-
| | <tt>'''n1 -lt n2 '''</tt>
| | <tt>'''n1 -lt n2 '''</tt>
| | n1 ist kleiner n2  
| | n1 ist kleiner n2
|-
|-
| | <tt>'''n1 -ne n2 '''</tt>
| | <tt>'''n1 -ne n2 '''</tt>
| | n1 ist ungleich n2  
| | n1 ist ungleich n2
|-
|-
|}
|}
Zeile 146: Zeile 146:
; Beispiele
; Beispiele
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
while test# -gt 0 Solange Argumente vorliegen
</syntaxhighlight>
</syntaxhighlight>
while test $# -gt 0    Solange Argumente vorliegen. . .
 
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
while [ -n "$1" ] Solange das erste Argument nicht leer ist
</syntaxhighlight>
</syntaxhighlight>
 
while [ -n "$1" ]    Solange das erste Argument nicht leer ist. . .
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [count -lt 10 ] Wenncount kleiner 10
</syntaxhighlight>
</syntaxhighlight>
if [ $count -lt 10 ]    Wenn $count kleiner 10. . .


{| class="wikitable sortable"  
{| class="wikitable sortable"
|-  
|-
| colspan="2" | '''Kombinierte Formen '''
| colspan="2" | '''Kombinierte Formen '''
|-
|-
| | <tt>'''(Bedingung) '''</tt>
| | <tt>'''(Bedingung) '''</tt>
| | Wahr, wenn die Bedingung zutrifft (wird für die Gruppierung verwendet). Den Klammern muss ein \ vorangestellt werden.
| | Wahr, wenn die Bedingung zutrifft (wird für die Gruppierung verwendet). Den Klammern muss ein \ vorangestellt werden
|-
|-
| | <tt>'''! Bedingung i '''</tt>
| | <tt>'''! Bedingung i '''</tt>
| | Wahr, wenn die Bedingung nicht zutrifft (NOT).
| | Wahr, wenn die Bedingung nicht zutrifft (NOT)
|-
|-
| | <tt>'''Bedingung1 -a Bedingung2'''</tt>
| | <tt>'''Bedingung1 -a Bedingung2'''</tt>
| | Wahr, wenn beide Bedingungen zutreffen (AND).
| | Wahr, wenn beide Bedingungen zutreffen (AND)
|-
|-
| | <tt>'''Bedingung1 -o Bedingung2'''</tt>
| | <tt>'''Bedingung1 -o Bedingung2'''</tt>
| | Wahr, wenn eine der beiden Bedingungen zutrifft (OR).
| | Wahr, wenn eine der beiden Bedingungen zutrifft (OR)
|-
|-
|}
|}


'''Beispiel'''
; Beispiel
Wenn das erste Argument keine lesbare oder reguläre Datei ist
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [ ! -r "$1" -o ! -f "$1" ]
</syntaxhighlight>
</syntaxhighlight>
if [ ! -r "$1" -o ! -f "$1" ]    Wenn das erste Argument keine lesbare oder reguläre Datei ist.
 


== Bedingte Anweisung (if - then - else) ==
== Bedingte Anweisung (if - then - else) ==
* Wichtig: Als Bedingung kann nicht nur der test-Befehl, sondern eine beliebige Folge von Kommados verwendet werden.
* Wichtig: Als Bedingung kann nicht nur der test-Befehl, sondern eine beliebige Folge von Kommados verwendet werden
* Jedes Kommando liefert einen Errorcode zurück, der bei erfolgreicher Ausführung gleich Null (true) und bei einem Fehler oder Abbruch ungleich Null (false) ist.
* Jedes Kommando liefert einen Errorcode zurück, der bei erfolgreicher Ausführung gleich Null (true) und bei einem Fehler oder Abbruch ungleich Null (false) ist
* Zum Testen einer Bedingung dient die if-Anweisung.
* Zum Testen einer Bedingung dient die if-Anweisung
* Jede Anweisung muss entweder in einer eigenen Zeile stehen oder durch einen Strichpunkt von den anderen Anweisungen getrennt werden.
* Jede Anweisung muss entweder in einer eigenen Zeile stehen oder durch einen Strichpunkt von den anderen Anweisungen getrennt werden
* Trotzdem verhät sich eine bedingte Anweisung - oder die Schleifenkonstrukte, die weiter unten behandelt werden - wie eine einzige Anweisung.
* Trotzdem verhät sich eine bedingte Anweisung - oder die Schleifenkonstrukte, die weiter unten behandelt werden - wie eine einzige Anweisung
* Somit ergibt sich eine starke Ähnlichkeit mit der Blockstruktur von C oder Pascal.
* Somit ergibt sich eine starke Ähnlichkeit mit der Blockstruktur von C oder Pascal
* Man kann dies ausprobieren, indem man eine if- oder while-Anweisung interaktiv eingibt. Solange nicht 'fi' bzw.&nbsp;'done' eingetippt wurde, erhält man den PS2-Prompt ('>').
* Man kann dies ausprobieren, indem man eine if- oder while-Anweisung interaktiv eingibt. Solange nicht 'fi' bzw.&nbsp;'done' eingetippt wurde, erhält man den PS2-Prompt ('>')


=== if ===
=== if ===
* Die if-Anweisung in der Shell-Programmierung macht das gleiche wie in allen anderen Programmiersprachen, sie testet eine Bedingung auf Wahrheit und macht davon den weiteren Ablauf des Programms abhängig.
* Die if-Anweisung in der Shell-Programmierung macht das gleiche wie in allen anderen Programmiersprachen, sie testet eine Bedingung auf Wahrheit und macht davon den weiteren Ablauf des Programms abhängig
* Die Syntax der if-Anweisung lautet wie folgt:
* Die Syntax der if-Anweisung lautet wie folgt
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
</syntaxhighlight>
</syntaxhighlight>
if Bedingung1
if Bedingung1
    then Befehle1
then Befehle1
[ elif Bedingung2
[ elif Bedingung2
    then Befehle2 ]
then Befehle2 ]
...
..
[ else Befehle3 ]
[ else Befehle3 ]
fi
fi


* Wenn die Bedingung1 erfüllt ist, werden die Befehle1 ausgeführt; andernfalls, wenn die Bedingung2 erfüllt ist, werden die Befehle2 ausgeführt. Trifft keine Bedingung zu, sollen die Befehle3 ausgeführt werden.
* Wenn die Bedingung1 erfüllt ist, werden die Befehle1 ausgeführt; andernfalls, wenn die Bedingung2 erfüllt ist, werden die Befehle2 ausgeführt. Trifft keine Bedingung zu, sollen die Befehle3 ausgeführt werden
* Bedingungen werden normalerweise mit dem Befehl test formuliert. Es kann aber auch der Rückgabewert jedes anderen Kommandos ausgewertet werden. Für Bedingungen, die auf jeden Fall zutreffen sollen steht der Null-Befehl (:) zur Verfügung.
* Bedingungen werden normalerweise mit dem Befehl test formuliert. Es kann aber auch der Rückgabewert jedes anderen Kommandos ausgewertet werden. Für Bedingungen, die auf jeden Fall zutreffen sollen steht der Null-Befehl (:) zur Verfügung


; Beispiele
; Beispiele
Man achte auf die Positionierung der Semikoli
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
# Füge eine 0 vor Zahlen kleiner 10 ein


Man achte auf die Positionierung der Semikoli.
counter=0
<syntaxhighlight lang="bash" highlight="1" line copy>
if [counter -lt 10 ]; then
number=0$counter; else number=$counter; fi
</syntaxhighlight>
</syntaxhighlight>
#!/bin/sh
  # Füge eine 0 vor Zahlen kleiner 10 ein:
counter=0
if [ $counter -lt 10 ]; then
number=0$counter; else number=$counter; fi


<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/bash
# Erstelle ein Verzeichnis, wenn es noch nicht existiert
dir=daten
if [ ! -edir ]; then
mkdirdir; fi # mkdir: Verzeichnis erstellen
</syntaxhighlight>
</syntaxhighlight>
#!/bin/bash
  # Erstelle ein Verzeichnis, wenn es noch nicht existiert:
dir=daten
if [ ! -e $dir ]; then
mkdir $dir; fi # mkdir: Verzeichnis erstellen


=== einseitiges if ===
=== einseitiges if ===
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if kommandoliste
then
kommandos
fi
</syntaxhighlight>
</syntaxhighlight>


if kommandoliste
then
      kommandos
fi


=== zweiseitiges if ===
=== zweiseitiges if ===
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if kommandoliste
then
kommandos
else
kommandos
fi
</syntaxhighlight>
</syntaxhighlight>
if kommandoliste
then
      kommandos
else
      kommandos
fi


=== Mehrstufiges if ===
=== Mehrstufiges if ===
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if kommandoliste1
then
kommandos
elif kommandoliste2
then
kommandos
elif ..
..
fi
</syntaxhighlight>
</syntaxhighlight>
if kommandoliste1
then
      kommandos
elif kommandoliste2
  then
        kommandos
elif ...
          ...
fi


=== Beispiele ===
=== Beispiele ===
Es soll eine Meldung ausgegeben werden, falls mehr als 5 Benutzer eingeloggt sind:
Es soll eine Meldung ausgegeben werden, falls mehr als 5 Benutzer eingeloggt sind
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
USERS=`who | wc -l` # Zeilen der who-Ausgabe zählen
if testUSERS -gt 5
then
echo "Mehr als 5 Benutzer am Geraet"
fi
</syntaxhighlight>
</syntaxhighlight>
USERS=`who | wc -l`  # Zeilen der who-Ausgabe zählen
if test $USERS -gt 5
then
  echo "Mehr als 5 Benutzer am Geraet"
fi


* Kürzere Variante
Kürzere Variante
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [(who | wc -l) -gt 5 ] ; then
echo "Mehr als 5 Benutzer am Geraet"
fi
</syntaxhighlight>
</syntaxhighlight>
if [ $(who | wc -l) -gt 5 ] ; then
  echo "Mehr als 5 Benutzer am Geraet"
fi


Man sollte bei der Entwicklung von Skripts aber ruhig mit der Langfassung beginnen und sich erst der Kurzfassung zuwenden, wenn man mehr Übung hat und die Langfassungen auf Anhieb funktionieren.
Man sollte bei der Entwicklung von Skripts aber ruhig mit der Langfassung beginnen und sich erst der Kurzfassung zuwenden, wenn man mehr Übung hat und die Langfassungen auf Anhieb funktionieren


Ein weiteres Beispiel zeigt eine Fehlerprüfung
Ein weiteres Beispiel zeigt eine Fehlerprüfung
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if test# -eq 0
then
echo "usage: sortiere filename" >&2
else
sort +1 -21 | lp
fi
</syntaxhighlight>
</syntaxhighlight>


if test $# -eq 0
; Beispiel
then
zeigt eine mehr oder weniger intelligente Anzeige für Dateien und Verzeichnisse. 'show' zeigt bei Dateien den Inhalt mit 'less' an und Verzeichnisse werden mit 'ls' präsentiert
  echo "usage: sortiere filename" >&2
else
  sort +1 -2 $1 | lp
fi
 
Das nächste Beispiel zeigt eine mehr oder weniger intelligente Anzeige für Dateien und Verzeichnisse. 'show' zeigt bei Dateien den Inhalt mit 'less' an und Verzeichnisse werden mit 'ls' präsentiert.
 
* Fehlt der Parameter, wird interaktiv nachgefragt
* Fehlt der Parameter, wird interaktiv nachgefragt
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [# -eq 0 ] # falls keine Angabe
then # interaktiv erfragen
echo -n "Bitte Namen eingeben: "
read DATEI
else
DATEI=$1
fi
if [ -fDATEI ] # wenn normale Datei
then # dann ausgeben
lessDATEI
elif [ -dDATEI ] # wenn aber Verzeichnis
then # dann Dateien zeigen
ls -CFDATEI
else # sonst Fehlermeldung
echo "cannot showDATEI"
fi
</syntaxhighlight>
</syntaxhighlight>
if [ $# -eq 0 ]                          # falls keine Angabe
then                                      # interaktiv erfragen
    echo -n "Bitte Namen eingeben: "
    read DATEI
else 
    DATEI=$1
fi
if  [ -f $DATEI ]                          # wenn normale Datei
then                                      # dann ausgeben
    less $DATEI 
elif [ -d $DATEI ]                        # wenn aber Verzeichnis
  then                                    # dann Dateien zeigen
      ls -CF $DATEI
    else                                  # sonst Fehlermeldung
      echo "cannot show $DATEI" 
fi


Das nächste Beispiel hängt eine Datei an eine andere Datei an; vorher erfolgt eine Prüfung der Zugriffsberechtigungen:
; Beispiel
Hängt eine Datei an eine andere Datei an; vorher erfolgt eine Prüfung der Zugriffsberechtigungen
append Datei1 Datei2


<tt>append Datei1 Datei2</tt>
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [ -r1 -a -w2 ]
then
cat1 >>2
else
echo "cannot append"
fi
</syntaxhighlight>
</syntaxhighlight>


if [ -r $1 -a -w $2 ]
Beim Vergleich von Zeichenketten sollten möglichst die Anführungszeichen (" ... ") verwendet werden, da sonst bei der Ersetzung durch die Shell unvollständige Test-Kommandos entstehen können
then
    cat $1 >> $2
else
    echo "cannot append"
fi
 
Beim Vergleich von Zeichenketten sollten möglichst die Anführungszeichen (" ... ") verwendet werden, da sonst bei der Ersetzung durch die Shell unvollständige Test-Kommandos entstehen können.


'''Beispiel'''
; Beispiel
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [ ! -n1 ] ; then
echo "Kein Parameter"
fi
</syntaxhighlight>
</syntaxhighlight>
if [ ! -n $1 ] ; then
    echo "Kein Parameter"
fi


Ist $1 wirklich nicht angegeben, wird das Kommando reduziert zu:
Ist1 wirklich nicht angegeben, wird das Kommando reduziert zu
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [ ! -n ] ; then ...
</syntaxhighlight>
</syntaxhighlight>


if [ ! -n ] ; then ....
Es ist also unvollständig und es erfolgt eine Fehlermeldung. Dagegen liefert
 
Es ist also unvollständig und es erfolgt eine Fehlermeldung. Dagegen liefert  
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [ ! -n "$1" ] ; then
echo "Kein Parameter"
fi
</syntaxhighlight>
</syntaxhighlight>


if [ ! -n "$1" ] ; then
bei fehlendem Parameter den korrekten Befehl
    echo "Kein Parameter"
fi
 
bei fehlendem Parameter den korrekten Befehl  
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
if [ ! -n "" ]
</syntaxhighlight>
</syntaxhighlight>


if [ ! -n "" ]
Bei fehlenden Anführungszeichen werden auch führende Leerzeichen der Variablenwerte oder Parameter eliminiert


Bei fehlenden Anführungszeichen werden auch führende Leerzeichen der Variablenwerte oder Parameter eliminiert.
; Weiteres Beispiel
 
Es kommt ab und zu vor, dass eine Userid wechselt oder dass die Gruppenzugehörigkeit von Dateien geändert werden muss. In solchen fällen helfen die beiden folgenden Skripts
'''Weiteres Beispiel'''
<syntaxhighlight lang="bash" highlight="" line copy>
 
#!/bin/sh
Es kommt ab und zu vor, dass eine Userid wechselt oder dass die Gruppenzugehörigkeit von Dateien geändert werden muss. In solchen fällen helfen die beiden folgenden Skripts:
# Change user-id
<syntaxhighlight lang="bash" highlight="1" line copy>
#
if [# -ne 2 ] ; then
echo "usage `basename0` <old id> <new id>"
exit
fi
find ~ -user1 -exec chown2 {} ";"
#!/bin/sh
# Change group-id
#
if [# -ne 2 ] ; then
echo "usage `basename0` <old id> <new id>"
exit
fi
find / -group1 -exec chgrp2 {} ";"
</syntaxhighlight>
</syntaxhighlight>
#!/bin/sh
  # Change user-id
  #
if [ $# -ne 2 ] ; then
  echo "usage `basename $0` <old id> <new id>"
  exit
fi
find ~ -user $1 -exec chown $2 {} ";"
#!/bin/sh
  # Change group-id
  #
if [ $# -ne 2 ] ; then
  echo "usage `basename $0` <old id> <new id>"
  exit
fi
find / -group $1 -exec chgrp $2 {} ";"


== case ==
== case ==
* Auch die case-Anweisung ist vergleichbar in vielen anderen Sprachen vorhanden.
* Auch die case-Anweisung ist vergleichbar in vielen anderen Sprachen vorhanden
* Sie dient, ähnlich wie die if-Anweisung, zur Fallunterscheidung. Allerdings wird hier nicht nur zwischen zwei Fällen unterschieden (Entweder / Oder), sondern es sind mehrere Fälle möglich.
* Sie dient, ähnlich wie die if-Anweisung, zur Fallunterscheidung. Allerdings wird hier nicht nur zwischen zwei Fällen unterschieden (Entweder / Oder), sondern es sind mehrere Fälle möglich
* Man kann die case-Anweisung auch durch eine geschachtelte if-Anweisung völlig umgehen, allerdings ist sie ein elegantes Mittel um den Code lesbar zu halten.
* Man kann die case-Anweisung auch durch eine geschachtelte if-Anweisung völlig umgehen, allerdings ist sie ein elegantes Mittel um den Code lesbar zu halten


Die Syntax der case-Anweisung lautet wie folgt
Die Syntax der case-Anweisung lautet wie folgt
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="" line>
case Wert in
Muster1) Befehle1;;
Muster2) Befehle2;;
..
esac
</syntaxhighlight>
</syntaxhighlight>


case Wert in
Wenn der Wert mit dem Muster1 übereinstimmt, wird die entsprechende Befehlsgruppe (Befehle1) ausgeführt, bei Übereinstimmung mit Muster2 werden die Kommandos der zweiten Befehlsgruppe (Befehle2) ausgeführt, und weitere
    Muster1) Befehle1;;
* Der letzte Befehl in jeder Gruppe muss mit ;; gekennzeichnet werden
    Muster2) Befehle2;;
* Das bedeutet für die Shell soviel wie springe zum nächsten esac, so dass die anderen Bedingungen nicht mehr überprüft werden
...
* In den Mustern sind die gleichen Meta-Zeichen erlaubt wie bei der Auswahl von Dateinamen
* Wenn in einer Zeile mehrere Muster angegeben werden sollen, müssen sie durch ein Pipezeichen (|, logisches ODER) getrennt werden
esac
 
Wenn der Wert mit dem Muster1 übereinstimmt, wird die entsprechende Befehlsgruppe (Befehle1) ausgeführt, bei Übereinstimmung mit Muster2 werden die Kommandos der zweiten Befehlsgruppe (Befehle2) ausgeführt, und weitere  
* Der letzte Befehl in jeder Gruppe muss mit ;; gekennzeichnet werden.
* Das bedeutet für die Shell soviel wie springe zum nächsten esac, so dass die anderen Bedingungen nicht mehr überprüft werden.
* In den Mustern sind die gleichen Meta-Zeichen erlaubt wie bei der Auswahl von Dateinamen.
* Wenn in einer Zeile mehrere Muster angegeben werden sollen, müssen sie durch ein Pipezeichen (|, logisches ODER) getrennt werden.


; Beispiele
; Beispiele
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
# Mit dem ersten Argument in der Befehlszeile
# wird die entsprechende Aktion festgelegt
case1 in # nimmt das erste Argument
Ja|Nein) response=1;;
*) echo "Unbekannte Option"; exit 1;;
esac
</syntaxhighlight>
</syntaxhighlight>
#!/bin/sh
  # Mit dem ersten Argument in der Befehlszeile
  # wird die entsprechende Aktion festgelegt:
case $1 in # nimmt das erste Argument
      Ja|Nein) response=1;;
            *) echo "Unbekannte Option"; exit 1;;
esac


<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
# Lies die Zeilen von der Standardeingabe, bis eine
# Zeile mit einem einzelnen Punkt eingegeben wird
while : # Null-Befehl
do
echo -e "Zum Beenden . eingeben ==> \c"
read line # read: Zeile von StdIn einlesen
case "$line" in
.) echo "Ausgefuehrt"
break;;
*) echo "$line" >>./message ;;
esac
done
</syntaxhighlight>
</syntaxhighlight>


#!/bin/sh
; case-Anweisung
  # Lies die Zeilen von der Standardeingabe, bis eine
Diese Anweisung erlaubt eine Mehrfachauswahl. Sie wird auch gerne deshalb verwendet, weil sie Muster mit Jokerzeichen und mehrere Muster für eine Auswahl erlauben
  # Zeile mit einem einzelnen Punkt eingegeben wird:
case selector in
while : # Null-Befehl
<syntaxhighlight lang="bash" highlight="1" line>
do
Muster-1) Kommandofolge 1 ;;
    echo -e "Zum Beenden . eingeben ==> \c"
Muster-2) Kommandofolge 2 ;;
    read line # read: Zeile von StdIn einlesen
...
    case "$line" in
          .) echo "Ausgefuehrt"
            break;;
          *) echo "$line" >>./message ;;
    esac
done


'''case-Anweisung'''
Muster-n) Kommandofolge n ;;
 
esac
Diese Anweisung erlaubt eine Mehrfachauswahl. Sie wird auch gerne deshalb verwendet, weil sie Muster mit Jokerzeichen und mehrere Muster für eine Auswahl erlauben
case selector in
<syntaxhighlight lang="bash" highlight="1" line copy>
</syntaxhighlight>
</syntaxhighlight>


      Muster-1) Kommandofolge 1 ;;
Die Variable <tt>selector</tt> (String) wird der Reihe nach mit den Mustern "Muster-1" bis "Muster-n" verglichen. Bei Gleichheit wird die nachfolgende Kommandofolge ausgeführt und dann nach der case-Anweisung (also hinter dem <tt>esac</tt>) fortgefahren. * In den Mustern sind Metazeichen (*, ?, []) erlaubt, im Selektor dagegen nicht
      Muster-2) Kommandofolge 2 ;;
* Das Muster * deckt sich mit jedem Selektor --> default-Ausgang. muss als letztes Muster in der case-Konstruktion stehen
              ....
* Vor der Klammer können mehrere Muster, getrennt durch <tt>| </tt>stehen
      Muster-n) Kommandofolge n ;;
esac
 
Die Variable <tt>selector</tt> (String) wird der Reihe nach mit den Mustern "Muster-1" bis "Muster-n" verglichen. Bei Gleichheit wird die nachfolgende Kommandofolge ausgeführt und dann nach der case-Anweisung (also hinter dem <tt>esac</tt>) fortgefahren. * In den Mustern sind Metazeichen (*, ?, []) erlaubt, im Selektor dagegen nicht.
* Das Muster * deckt sich mit jedem Selektor --> default-Ausgang. muss als letztes Muster in der case-Konstruktion stehen.
* Vor der Klammer können mehrere Muster, getrennt durch <tt>| </tt>stehen.


'''Das Zeichen <tt>| </tt>bildet eine Oder-Bedingung:'''
'''Das Zeichen <tt>| </tt>bildet eine Oder-Bedingung:'''
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
case selector in
Muster1) Kommandofolge1 ;;
Muster2 | Muster3) Kommandofolge2 ;;
*) Kommandofolge3 ;;
esac
</syntaxhighlight>
</syntaxhighlight>
case selector in
      Muster1)              Kommandofolge1 ;;
      Muster2 | Muster3)    Kommandofolge2 ;;
      *)                    Kommandofolge3 ;;
esac


; Beispiel 1
; Beispiel 1
Automatische Bearbeitung von Quell- und Objekt-Dateien. Der Aufruf erfolgt mit 'compile Datei'.
Automatische Bearbeitung von Quell- und Objekt-Dateien. Der Aufruf erfolgt mit 'compile Datei'
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
case1 in
*.s) as1 ;; # Assembler aufrufen
*.c) cc -c1 ;; # C-Compiler aufrufen
*.o) cc1 -o prog ;; # C-Compiler als Linker
*) echo "invalid parameter:1";;
esac
</syntaxhighlight>
</syntaxhighlight>
case $1 in
    *.s) as $1 ;;                        # Assembler aufrufen
    *.c) cc -c $1 ;;                    # C-Compiler aufrufen
    *.o) cc $1 -o prog ;;                # C-Compiler als Linker
      *) echo "invalid parameter: $1";;
esac


; Beispiel 2
; Beispiel 2
Menü mit interaktiver Eingabe
Menü mit interaktiver Eingabe
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
while : # Endlosschleife
do
tput clear # Schirm löschen und Menütext ausgeben
echo " +---------------------------------+"
echo " | 0 --> Ende |"
echo " | 1 --> Datum und Uhrzeit |"
echo " | 2 --> aktuelles Verzeichnis |"
echo " | 3 --> Inhaltsverzeichnis |"
echo " | 4 --> Mail |"
echo "+----------------------------------+"
echo "Eingabe: \c" # kein Zeilenvorschub
read ANTW
caseANTW in
0) kill -9 0 ;; # und tschuess
1) date ;;
2) pwd ;;
3) ls -CF ;;
4) elm ;;
*) echo "Falsche Eingabe!" ;;
esac
done
</syntaxhighlight>
</syntaxhighlight>
while :  # Endlosschleife
do
tput clear  # Schirm löschen und Menütext ausgeben
    echo " +---------------------------------+" 
    echo " | 0 --> Ende                      |"
    echo " | 1 --> Datum und Uhrzeit        |"
    echo " | 2 --> aktuelles Verzeichnis    |"
    echo " | 3 --> Inhaltsverzeichnis        |"
    echo " | 4 --> Mail                      |"
    echo "+----------------------------------+"
    echo "Eingabe: \c"  # kein Zeilenvorschub
    read ANTW
    case $ANTW in
    0) kill -9 0 ;; # und tschuess
    1) date ;; 
    2) pwd ;;
    3) ls -CF ;;
    4) elm ;;
      *) echo "Falsche Eingabe!" ;;
    esac
done


== for-Anweisung ==
== for-Anweisung ==
* Diese Schleifenanweisung hat zwei Ausprägungen, mit einer Liste der zu bearbeitenden Elemente oder mit den Kommandozeilenparametern.
* Diese Schleifenanweisung hat zwei Ausprägungen, mit einer Liste der zu bearbeitenden Elemente oder mit den Kommandozeilenparametern
* Dieses Konstrukt ähnelt nur auf den ersten Blick seinen Pendants aus anderen Programmiersprachen.
* Dieses Konstrukt ähnelt nur auf den ersten Blick seinen Pendants aus anderen Programmiersprachen
* In anderen Sprachen wird die for-Schleife meistens dazu benutzt, eine Zählvariable über einen bestimmten Wertebereich iterieren zu lassen (for i = 1 to 100...next).
* In anderen Sprachen wird die for-Schleife meistens dazu benutzt, eine Zählvariable über einen bestimmten Wertebereich iterieren zu lassen (for i = 1 to 100...next)
* In der Shell dagegen wird die Laufvariable nicht mit aufeinander folgenden Zahlen belegt, sondern mit einzelnen Werten aus einer anzugebenden Liste.
* In der Shell dagegen wird die Laufvariable nicht mit aufeinander folgenden Zahlen belegt, sondern mit einzelnen Werten aus einer anzugebenden Liste
* Wenn man eine Laufvariable benötigt, muss man dazu die while-Schleife einsetzen.
* Wenn man eine Laufvariable benötigt, muss man dazu die while-Schleife einsetzen


Die Syntax der for-Schleife lautet wie folgt:
Die Syntax der for-Schleife lautet wie folgt
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
for x [ in Liste ]
do
Befehle
done
</syntaxhighlight>
</syntaxhighlight>


for x [ in Liste ]
Die Befehle werden ausgeführt, wobei der Variablen x nacheinander die Werte aus der Liste zugewiesen werden
do
* Wie man sieht, ist die Angabe der Liste optional, wenn sie nicht angegeben wird, nimmt x der Reihe nach alle Werte aus@ (in dieser vordefinierten Variablen liegen die Aufrufparameter) an
* Wenn die Ausführung eines Schleifendurchlaufs bzw.&nbsp;der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw.&nbsp;break benutzt werden
Befehle
done
 
Die Befehle werden ausgeführt, wobei der Variablen x nacheinander die Werte aus der Liste zugewiesen werden.
* Wie man sieht, ist die Angabe der Liste optional, wenn sie nicht angegeben wird, nimmt x der Reihe nach alle Werte aus $@ (in dieser vordefinierten Variablen liegen die Aufrufparameter) an.
* Wenn die Ausführung eines Schleifendurchlaufs bzw.&nbsp;der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw.&nbsp;break benutzt werden.


=== for-Schleife mit Liste ===
=== for-Schleife mit Liste ===
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
for selector in liste
do
Kommandofolge
done
</syntaxhighlight>
</syntaxhighlight>


for selector in liste
Die Selektor-Variable wird nacheinander durch die Elemente der Liste ersetzt und die Schleife mit der Selektor-Variablen ausgeführt
  do
  Kommandofolge
done


Die Selektor-Variable wird nacheinander durch die Elemente der Liste ersetzt und die Schleife mit der Selektor-Variablen ausgeführt.
; Beispiele
<syntaxhighlight lang="bash" highlight="1" line copy>
for X in hans heinz karl luise do echoX done


; Beispiele
Ausgabe
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
hans
heinz
karl
luise
</syntaxhighlight>
</syntaxhighlight>
for X in hans heinz karl luise do echo $X done
Das Programm hat folgende Ausgabe:
hans
heinz
karl
luise


<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
for FILE in *.txt # drucke alle Textdateien
do # im aktuellen Verzeichnis
lprFILE
done
for XX inVAR # geht auch mit
do
echoXX
done
</syntaxhighlight>
</syntaxhighlight>


for FILE in *.txt # drucke alle Textdateien
Durchsuche Kapitel zur Erstellung einer Wortliste (wie fgrep -f)
  do # im aktuellen Verzeichnis
  lpr $FILE
done
for XX in $VAR # geht auch mit
  do
  echo $XX
done
 
Durchsuche Kapitel zur Erstellung einer Wortliste (wie fgrep -f):
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
for item in(cat program_list) # cat: Datei ausgeben
do
echo "Pruefung der Kapitel auf"
echo "Referenzen zum Programmitem ..."
grep -c "$item.[co]" chap* # grep: nach Muster suchen
done
</syntaxhighlight>
</syntaxhighlight>


for item in $(cat program_list) # cat: Datei ausgeben
do
    echo "Pruefung der Kapitel auf"
    echo "Referenzen zum Programm $item ..."
    grep -c "$item.[co]" chap* # grep: nach Muster suchen
done


=== for-Schleife mit Parametern ===
=== for-Schleife mit Parametern ===
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
for selector
do
Kommandofolge
done
</syntaxhighlight>
</syntaxhighlight>


for selector
Die Selektor-Variable wird nacheinander durch die Parameter1 bisn ersetzt und mit diesen Werten die Schleife durchlaufen. Es gibt also# Schleifendurchläufe
  do
  Kommandofolge
done


Die Selektor-Variable wird nacheinander durch die Parameter $1 bis $n ersetzt und mit diesen Werten die Schleife durchlaufen. Es gibt also $# Schleifendurchläufe.
; Beispiel
Die Prozedur 'makebak' erzeugt für die in der Parameterliste angegebenen Dateien eine .bak-Datei
<syntaxhighlight lang="bash" highlight="1" line copy>
for FF
do
cpFF{FF}.bak
done
#!/bin/sh
# Seitenweises Formatieren der Dateien, die auf der
# Befehlszeile angegeben wurden, und speichern des
# jeweiligen Ergebnisses


'''Beispiel'''
for file do
prfile >file.tmp # pr: Formatiert Textdateien
done
# Ermittle einen Ein-Wort-Titel aus jeder Datei und
# verwende ihn als neuen Dateinamen


Die Prozedur 'makebak' erzeugt für die in der Parameterliste angegebenen Dateien eine .bak-Datei.  
for file do
<syntaxhighlight lang="bash" highlight="1" line copy>
name=`sed -n 's/NAME: //p'file`
# sed: Skriptsprache zur Textformatierung
mvfilename
# mv: Datei verschieben bzw.&nbsp;umbenennen
done
</syntaxhighlight>
</syntaxhighlight>
for FF
  do
  cp $FF ${FF}.bak
done
#!/bin/sh   
  # Seitenweises Formatieren der Dateien, die auf der
  # Befehlszeile angegeben wurden, und speichern des
  # jeweiligen Ergebnisses:
for file do
    pr $file > $file.tmp # pr: Formatiert Textdateien
done
# Ermittle einen Ein-Wort-Titel aus jeder Datei und
  # verwende ihn als neuen Dateinamen:
for file do
    name=`sed -n 's/NAME: //p' $file`
      # sed: Skriptsprache zur Textformatierung
    mv $file $name
      # mv: Datei verschieben bzw.&nbsp;umbenennen
done


== while ==
== while ==
Die while-Schleife ist wieder ein Konstrukt, das einem aus vielen anderen Sprachen bekannt ist:
Die while-Schleife ist wieder ein Konstrukt, das einem aus vielen anderen Sprachen bekannt ist


Die kopfgesteuerte Schleife. Die Syntax der while-Schleife lautet wie folgt:
Die kopfgesteuerte Schleife. Die Syntax der while-Schleife lautet wie folgt
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
while Bedingung
do
Befehle
done
</syntaxhighlight>
</syntaxhighlight>


while Bedingung
Die Befehle werden so lange ausgeführt, wie die Bedingung erfüllt ist
do
Befehle
done


Die Befehle werden so lange ausgeführt, wie die Bedingung erfüllt ist.
Dabei wird die Bedingung vor der Ausführung der Befehle überprüft. Die Bedingung wird dabei üblicherweise, genau wie bei der if-Anweisung, mit dem Befehl test formuliert


Dabei wird die Bedingung vor der Ausführung der Befehle überprüft. Die Bedingung wird dabei üblicherweise, genau wie bei der if-Anweisung, mit dem Befehl test formuliert.
Wenn die Ausführung eines Schleifendurchlaufs bzw.&nbsp;der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw.&nbsp;break benutzt werden
 
Wenn die Ausführung eines Schleifendurchlaufs bzw.&nbsp;der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw.&nbsp;break benutzt werden.


; Beispiele
; Beispiele
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
# Zeilenweise Ausgabe aller Aufrufparameter
while [ -n "$1"]; do
echo1
shift # mit shift werden die Parameter nach
# Links geshiftet (aus2 wird1)
done
</syntaxhighlight>
</syntaxhighlight>


#!/bin/sh
  # Zeilenweise Ausgabe aller Aufrufparameter:
while [ -n "$1"]; do
  echo $1
  shift  # mit shift werden die Parameter nach
    # Links geshiftet (aus $2 wird $1)
done 


; Zählschleife
; Zählschleife
In anderen Sprachen kann man mit der for-Schleife eine Zählvariable über einen bestimmten Wertebereich iterieren lassen (for i = 1 to 100...next)


In anderen Sprachen kann man mit der for-Schleife eine Zählvariable über einen bestimmten Wertebereich iterieren lassen (for i = 1 to 100...next).
Da das mit der for-Schleife der Shell nicht geht, ersetzt man die Funktion durch geschickte Anwendung der while-Schleife
 
Da das mit der for-Schleife der Shell nicht geht, ersetzt man die Funktion durch geschickte Anwendung der while-Schleife:
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
# Ausgabe der Zahlen von 1 bis 100
i=1
while [i -le 100 ]
do
echoi
i=`expri + 1`
done
</syntaxhighlight>
</syntaxhighlight>


#!/bin/sh
  # Ausgabe der Zahlen von 1 bis 100:
i=1
while [ $i -le 100 ]
do
    echo $i
    i=`expr $i + 1`
done


; Weitere Beispiele
; Weitere Beispiele
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
while who | grep "^root "
do sleep 30
done
echo Die Katze ist aus dem Haus, Zeit, dass die Mäuse tanzen!
</syntaxhighlight>
</syntaxhighlight>
#!/bin/sh
while who | grep "^root "
do sleep 30
done
echo Die Katze ist aus dem Haus, Zeit, dass die Mäuse tanzen!


; Ergebniswert eines Kommandos
; Ergebniswert eines Kommandos
 
Als Bedingung kann nicht nur eine "klassische" Bedingung (<tt>test</tt> oder <tt>[ ]</tt>) sondern auch der Ergebniswert eines Kommandos oder einer Kommandofolge verwendet werden
Als Bedingung kann nicht nur eine "klassische" Bedingung (<tt>test</tt> oder <tt>[ ]</tt>) sondern auch der Ergebniswert eines Kommandos oder einer Kommandofolge verwendet werden.
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
while Bedingung
do
Kommandofolge
done
</syntaxhighlight>
</syntaxhighlight>


while Bedingung
Solange der Bedingungsausdruck den Wert 'true' liefert, wird die Schleife ausgeführt
  do
  Kommandofolge
  done
 
Solange der Bedingungsausdruck den Wert 'true' liefert, wird die Schleife ausgeführt.


; Warten auf eine Datei (beispielsweise vom Hintergrundprozess)
; Warten auf eine Datei (beispielsweise vom Hintergrundprozess)
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
</syntaxhighlight>
while [ ! -f foo ]
 
do
while [ ! -f foo ]
sleep 10 # Wichtig damit die Prozesslast nicht zu hoch wird
  do
done
  sleep 10 # Wichtig damit die Prozesslast nicht zu hoch wird
done


; Pausenfüller für das Terminal Abbruch mit DEL-Taste
; Pausenfüller für das Terminal Abbruch mit DEL-Taste
while :
while  
  do
do
  tput clear # BS löschen
tput clear # BS löschen
  echo -e "\n\n\n\n\n" # 5 Leerzeilen
echo -e "\n\n\n\n\n" # 5 Leerzeilen
  banner $(date '+ %T ') # Uhrzeit groß
banner(date '+ %T ') # Uhrzeit groß
  sleep 10 # 10s Pause
sleep 10 # 10s Pause
done
done
 
</syntaxhighlight>


; Umbenennen von Dateien durch Anhängen eines Suffix
; Umbenennen von Dateien durch Anhängen eines Suffix
Zeile 701: Zeile 675:
</syntaxhighlight>
</syntaxhighlight>


 
# Aufruf change suffix datei(en)
# Aufruf change suffix datei(en)
if [# -lt 2 ] ; then
if [ $# -lt 2 ] ; then
echo "Usage: `basename0` suffix file(s)"
  echo "Usage: `basename $0` suffix file(s)"
else
else
SUFF=$1 # Suffix speichern
  SUFF=$1 # Suffix speichern
shift
  shift
while [# -ne 0 ] # solange Parameter da sind
  while [ $# -ne 0 ] # solange Parameter da sind
do
  do
mv1{1}.$SUFF # umbenennen
  mv $1 ${1}.$SUFF # umbenennen
shift
  shift
done
  done
fi
fi


; Umbenennen von Dateien durch Anhängen eines Suffix Variante 2 mit for
; Umbenennen von Dateien durch Anhängen eines Suffix Variante 2 mit for
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
# Aufruf change suffix datei(en)
if [# -lt 2 ] ; then
echo "Usage: `basename0` suffix file(s)"
else
SUFF=$1 # Suffix speichern
shift
for FILE
do
mvFILE{FILE}.$SUFF # umbenennen
shift
done
fi
</syntaxhighlight>
</syntaxhighlight>
# Aufruf change suffix datei(en)
if [ $# -lt 2 ] ; then
  echo "Usage: `basename $0` suffix file(s)"
else
  SUFF=$1 # Suffix speichern
  shift
  for FILE
  do
  mv $FILE ${FILE}.$SUFF # umbenennen
  shift
  done
fi


== until ==
== until ==
Diese Anweisung ist identisch zu einer <tt>while</tt>-Schleife mit negierter Bedingung.
Diese Anweisung ist identisch zu einer <tt>while</tt>-Schleife mit negierter Bedingung


Als Bedingung kann nicht nur eine "klassische" Bedingung (<tt>test</tt> oder <tt>[ ]</tt>) sondern auch der Ergebniswert eines Kommandos oder einer Kommandofolge verwendet werden.
Als Bedingung kann nicht nur eine "klassische" Bedingung (<tt>test</tt> oder <tt>[ ]</tt>) sondern auch der Ergebniswert eines Kommandos oder einer Kommandofolge verwendet werden
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
until Bedingung
do
Kommandofolge
done
</syntaxhighlight>
</syntaxhighlight>


until Bedingung
Die Schleife wird so lange abgearbeitet, bis Bedingungsausdruck einen Wert ungleich Null liefert
  do
  Kommandofolge
done
 
Die Schleife wird so lange abgearbeitet, bis Bedingungsausdruck einen Wert ungleich Null liefert.


'''Beispiel'''
; Beispiel
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
# warten auf Datei foo
until [ -f foo ]
do
sleep 10
done
</syntaxhighlight>
</syntaxhighlight>
# warten auf Datei foo
until [ -f foo ]
  do
  sleep 10
done


; Warten auf einen Benutzer
; Warten auf einen Benutzer
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
# warten, bis sich der Benutzer hans eingeloggt hat
TT=`who | grep -c "hans"`
until [TT -gt 0 ]
do
sleep 10
TT=`who | grep -c "hans"`
done
# warten, bis sich der Benutzer hans eingeloggt hat
# Variante 2 - kuerzer
until [ `who | grep -c "hans"` -gt 0 ]
do
sleep 10
done
</syntaxhighlight>
</syntaxhighlight>


# warten, bis sich der Benutzer hans eingeloggt hat
Die Befehle werden ausgeführt, bis die Bedingung erfüllt ist. Die Bedingung wird dabei üblicherweise, genau wie bei der if-Anweisung, mit dem Befehl test formuliert
TT=`who | grep -c "hans"`
until [ $TT -gt 0 ]
  do
  sleep 10
  TT=`who | grep -c "hans"`
done
# warten, bis sich der Benutzer hans eingeloggt hat
  # Variante 2 - kuerzer
until [ `who | grep -c "hans"` -gt 0 ]
  do
  sleep 10
done


Die Befehle werden ausgeführt, bis die Bedingung erfüllt ist. Die Bedingung wird dabei üblicherweise, genau wie bei der if-Anweisung, mit dem Befehl test formuliert.  
Wenn die Ausführung eines Schleifendurchlaufs bzw.&nbsp;der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw.&nbsp;break benutzt werden


Wenn die Ausführung eines Schleifendurchlaufs bzw.&nbsp;der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw.&nbsp;break benutzt werden.
; Beispiel
 
Hier wird die Bedingung nicht per test, sondern mit dem Rückgabewert des Programms grep formuliert
'''Beispiel'''
 
Hier wird die Bedingung nicht per test, sondern mit dem Rückgabewert des Programms grep formuliert.
<syntaxhighlight lang="bash" highlight="1" line copy>
<syntaxhighlight lang="bash" highlight="1" line copy>
#!/bin/sh
#!/bin/sh
# Warten, bis sich der Administrator einloggt:
# Warten, bis sich der Administrator einloggt


until who | grep "root"; do
until who | grep "root"; do
# who: Liste der Benutzer
# who: Liste der Benutzer
# grep: Suchen nach Muster
# grep: Suchen nach Muster
    sleep 30 # sleep: warten
sleep 30 # sleep: warten
done
done
echo "Der Meister ist anwesend"
echo "Der Meister ist anwesend"
</syntaxhighlight>
</syntaxhighlight>


[[Kategorie:Bash/Scripting]]
[[Kategorie:Bash/Scripting]]

Version vom 6. Oktober 2025, 12:53 Uhr

Kontrollstrukturen ermöglichen den Ablauf eines Linux-Shell-Skripts zu steuern (Bedingte Verzweigungen, Schleifen, Fallunterscheidungen)

Bedingungen testen

Das wichtigste Kommando ist 'test', mit dem man mannigfache Bedingungen testen kann

test Argument

Dieses Kommando prüft eine Bedingung und liefert 'true' (0), falls die Bedingung erfüllt ist und 'false' (1), falls die Bedingung nicht erfüllt ist. Der Fehlerwert 2 wird zurückgegeben, wenn das Argument syntaktisch falsch ist (meist durch Ersetzung hervorgerufen)

Es lassen sich Dateien, Zeichenketten und Integer-Zahlen (16 Bit, bei Linux 32 Bit) überprüfen. Das Argument von Test besteht aus einer Testoption und einem Operanden, der ein Dateiname oder eine Shell-Variable (Inhalt: String oder Zahl) sein kann

In bestimmten Fällen können auf der rechten Seite eines Vergleichs auch Strings oder Zahlen stehen - bei der Ersetzung von leeren Variablen kann es aber zu Syntaxfehlern kommen. Weiterhin lassen sich mehrere Argumente logisch verknüpfen (UND, ODER, NICHT). Beispiel

test -w /etc/passwd

mit der Kommandoverkettung lassen sich so schon logische Entscheidungen treffen, beispielsweise

test -w /etc/passwd && echo "Du bist ROOT"

Normalerweise kann statt 'test' das Argument auch in eckigen Klammern gesetzt werden. Die Klammern müssen von Leerzeichen umschlossen werden

[ -w /etc/passwd ]
Operationen
Dateitests
-b Datei Die Datei existiert und ist ein blockorientiertes Gerät
-c Datei Die Datei existiert und ist ein zeichenorientiertes Gerät
-d Datei Die Datei existiert und ist ein Verzeichnis
-e Datei Datei existiert
-f Datei Die Datei existiert und ist eine reguläre Datei
-g Datei Die Datei existiert und das Gruppen-ID-Bit ist gesetzt
-h Datei Die Datei existiert und ist ein symbolischer Link
-k Datei Die Datei existiert und das Sticky-Bit ist gesetzt
-p Datei Die Datei existiert und ist eine Named Pipe
-r Datei Die Datei existiert und ist lesbar
-s Datei Die Datei existiert und ist nicht leer
-t [n] DATEI-Descriptor FD (Standard: Standardausgabe) ist auf Tty offen
-u Datei Die Datei existiert und das Setuid-Bit ist gesetzt
-w Datei Die Datei existiert und ist beschreibbar
-x Datei Die Datei existiert und ist ausführbar
Datei1 -nt Datei2 Datei1 ist neuer als Datei2
Datei1 -ot Datei2 Datei1 ist älter als Datei2
Datei1 -ef Datei2 Beide Dateien belegen dieselbe Inode auf demselben Gerät
Beispiel

Wenn ein Verzeichnis RCS existiert

if [ -d RCS ] Wenn ein Verzeichnis RCS existiert
Bedingungen für Zeichenfolgen
-n s1 Die Länge der Zeichenfolge s1 ist ungleich Null
-z s1 Die Länge der Zeichenfolge s1 ist gleich Null
s1 = s2 Die Zeichenfolgen s1 und s2 sind identisch
s1 != s2 Die Zeichenfolgen s1 und s2 sind nicht identisch
Zeichenfolge Die Zeichenfolge ist nicht Null
Beispiel

Wenn dieAntwort nicht "j" ist

if [ "$Antwort" != "j" ]
Ganzzahlvergleiche:
n1 -eq n2 n1 ist gleich n2
n1 -ge n2 n1 ist größer oder gleich n2
n1 -gt n2 n1 ist größer als n2
n1 -le n2 n1 ist kleiner oder gleich n2
n1 -lt n2 n1 ist kleiner n2
n1 -ne n2 n1 ist ungleich n2
Beispiele
while test# -gt 0 Solange Argumente vorliegen
while [ -n "$1" ] Solange das erste Argument nicht leer ist
if [count -lt 10 ] Wenncount kleiner 10
Kombinierte Formen
(Bedingung) Wahr, wenn die Bedingung zutrifft (wird für die Gruppierung verwendet). Den Klammern muss ein \ vorangestellt werden
! Bedingung i Wahr, wenn die Bedingung nicht zutrifft (NOT)
Bedingung1 -a Bedingung2 Wahr, wenn beide Bedingungen zutreffen (AND)
Bedingung1 -o Bedingung2 Wahr, wenn eine der beiden Bedingungen zutrifft (OR)
Beispiel

Wenn das erste Argument keine lesbare oder reguläre Datei ist

if [ ! -r "$1" -o ! -f "$1" ]


Bedingte Anweisung (if - then - else)

  • Wichtig: Als Bedingung kann nicht nur der test-Befehl, sondern eine beliebige Folge von Kommados verwendet werden
  • Jedes Kommando liefert einen Errorcode zurück, der bei erfolgreicher Ausführung gleich Null (true) und bei einem Fehler oder Abbruch ungleich Null (false) ist
  • Zum Testen einer Bedingung dient die if-Anweisung
  • Jede Anweisung muss entweder in einer eigenen Zeile stehen oder durch einen Strichpunkt von den anderen Anweisungen getrennt werden
  • Trotzdem verhät sich eine bedingte Anweisung - oder die Schleifenkonstrukte, die weiter unten behandelt werden - wie eine einzige Anweisung
  • Somit ergibt sich eine starke Ähnlichkeit mit der Blockstruktur von C oder Pascal
  • Man kann dies ausprobieren, indem man eine if- oder while-Anweisung interaktiv eingibt. Solange nicht 'fi' bzw. 'done' eingetippt wurde, erhält man den PS2-Prompt ('>')

if

  • Die if-Anweisung in der Shell-Programmierung macht das gleiche wie in allen anderen Programmiersprachen, sie testet eine Bedingung auf Wahrheit und macht davon den weiteren Ablauf des Programms abhängig
  • Die Syntax der if-Anweisung lautet wie folgt

if Bedingung1 then Befehle1 [ elif Bedingung2 then Befehle2 ] .. [ else Befehle3 ] fi

  • Wenn die Bedingung1 erfüllt ist, werden die Befehle1 ausgeführt; andernfalls, wenn die Bedingung2 erfüllt ist, werden die Befehle2 ausgeführt. Trifft keine Bedingung zu, sollen die Befehle3 ausgeführt werden
  • Bedingungen werden normalerweise mit dem Befehl test formuliert. Es kann aber auch der Rückgabewert jedes anderen Kommandos ausgewertet werden. Für Bedingungen, die auf jeden Fall zutreffen sollen steht der Null-Befehl (:) zur Verfügung
Beispiele

Man achte auf die Positionierung der Semikoli

#!/bin/sh
# Füge eine 0 vor Zahlen kleiner 10 ein

counter=0
if [counter -lt 10 ]; then
number=0$counter; else number=$counter; fi
#!/bin/bash
# Erstelle ein Verzeichnis, wenn es noch nicht existiert
dir=daten
if [ ! -edir ]; then
mkdirdir; fi # mkdir: Verzeichnis erstellen

einseitiges if

if kommandoliste
then
kommandos
fi


zweiseitiges if

if kommandoliste
then
kommandos
else
kommandos
fi

Mehrstufiges if

if kommandoliste1
then
kommandos
elif kommandoliste2
then
kommandos
elif ..
..
fi

Beispiele

Es soll eine Meldung ausgegeben werden, falls mehr als 5 Benutzer eingeloggt sind

USERS=`who | wc -l` # Zeilen der who-Ausgabe zählen
if testUSERS -gt 5
then
echo "Mehr als 5 Benutzer am Geraet"
fi

Kürzere Variante

if [(who | wc -l) -gt 5 ] ; then
echo "Mehr als 5 Benutzer am Geraet"
fi

Man sollte bei der Entwicklung von Skripts aber ruhig mit der Langfassung beginnen und sich erst der Kurzfassung zuwenden, wenn man mehr Übung hat und die Langfassungen auf Anhieb funktionieren

Ein weiteres Beispiel zeigt eine Fehlerprüfung

if test# -eq 0
then
echo "usage: sortiere filename" >&2
else
sort +1 -21 | lp
fi
Beispiel

zeigt eine mehr oder weniger intelligente Anzeige für Dateien und Verzeichnisse. 'show' zeigt bei Dateien den Inhalt mit 'less' an und Verzeichnisse werden mit 'ls' präsentiert

  • Fehlt der Parameter, wird interaktiv nachgefragt
if [# -eq 0 ] # falls keine Angabe
then # interaktiv erfragen
echo -n "Bitte Namen eingeben: "
read DATEI
else
DATEI=$1
fi
if [ -fDATEI ] # wenn normale Datei
then # dann ausgeben
lessDATEI
elif [ -dDATEI ] # wenn aber Verzeichnis
then # dann Dateien zeigen
ls -CFDATEI
else # sonst Fehlermeldung
echo "cannot showDATEI"
fi
Beispiel

Hängt eine Datei an eine andere Datei an; vorher erfolgt eine Prüfung der Zugriffsberechtigungen append Datei1 Datei2

if [ -r1 -a -w2 ]
then
cat1 >>2
else
echo "cannot append"
fi

Beim Vergleich von Zeichenketten sollten möglichst die Anführungszeichen (" ... ") verwendet werden, da sonst bei der Ersetzung durch die Shell unvollständige Test-Kommandos entstehen können

Beispiel
if [ ! -n1 ] ; then
echo "Kein Parameter"
fi

Ist1 wirklich nicht angegeben, wird das Kommando reduziert zu

if [ ! -n ] ; then ...

Es ist also unvollständig und es erfolgt eine Fehlermeldung. Dagegen liefert

if [ ! -n "$1" ] ; then
echo "Kein Parameter"
fi

bei fehlendem Parameter den korrekten Befehl

if [ ! -n "" ]

Bei fehlenden Anführungszeichen werden auch führende Leerzeichen der Variablenwerte oder Parameter eliminiert

Weiteres Beispiel

Es kommt ab und zu vor, dass eine Userid wechselt oder dass die Gruppenzugehörigkeit von Dateien geändert werden muss. In solchen fällen helfen die beiden folgenden Skripts

#!/bin/sh
# Change user-id
#
if [# -ne 2 ] ; then
echo "usage `basename0` <old id> <new id>"
exit
fi
find ~ -user1 -exec chown2 {} ";"
#!/bin/sh
# Change group-id
#
if [# -ne 2 ] ; then
echo "usage `basename0` <old id> <new id>"
exit
fi
find / -group1 -exec chgrp2 {} ";"

case

  • Auch die case-Anweisung ist vergleichbar in vielen anderen Sprachen vorhanden
  • Sie dient, ähnlich wie die if-Anweisung, zur Fallunterscheidung. Allerdings wird hier nicht nur zwischen zwei Fällen unterschieden (Entweder / Oder), sondern es sind mehrere Fälle möglich
  • Man kann die case-Anweisung auch durch eine geschachtelte if-Anweisung völlig umgehen, allerdings ist sie ein elegantes Mittel um den Code lesbar zu halten

Die Syntax der case-Anweisung lautet wie folgt

case Wert in
Muster1) Befehle1;;
Muster2) Befehle2;;
..
esac

Wenn der Wert mit dem Muster1 übereinstimmt, wird die entsprechende Befehlsgruppe (Befehle1) ausgeführt, bei Übereinstimmung mit Muster2 werden die Kommandos der zweiten Befehlsgruppe (Befehle2) ausgeführt, und weitere

  • Der letzte Befehl in jeder Gruppe muss mit ;; gekennzeichnet werden
  • Das bedeutet für die Shell soviel wie springe zum nächsten esac, so dass die anderen Bedingungen nicht mehr überprüft werden
  • In den Mustern sind die gleichen Meta-Zeichen erlaubt wie bei der Auswahl von Dateinamen
  • Wenn in einer Zeile mehrere Muster angegeben werden sollen, müssen sie durch ein Pipezeichen (|, logisches ODER) getrennt werden
Beispiele
#!/bin/sh
# Mit dem ersten Argument in der Befehlszeile
# wird die entsprechende Aktion festgelegt

case1 in # nimmt das erste Argument
Ja|Nein) response=1;;
*) echo "Unbekannte Option"; exit 1;;
esac
#!/bin/sh
# Lies die Zeilen von der Standardeingabe, bis eine
# Zeile mit einem einzelnen Punkt eingegeben wird
while : # Null-Befehl
do
echo -e "Zum Beenden . eingeben ==> \c"
read line # read: Zeile von StdIn einlesen
case "$line" in
.) echo "Ausgefuehrt"
break;;
*) echo "$line" >>./message ;;
esac
done
case-Anweisung

Diese Anweisung erlaubt eine Mehrfachauswahl. Sie wird auch gerne deshalb verwendet, weil sie Muster mit Jokerzeichen und mehrere Muster für eine Auswahl erlauben case selector in

Muster-1) Kommandofolge 1 ;;
Muster-2) Kommandofolge 2 ;;
...

Muster-n) Kommandofolge n ;;
esac

Die Variable selector (String) wird der Reihe nach mit den Mustern "Muster-1" bis "Muster-n" verglichen. Bei Gleichheit wird die nachfolgende Kommandofolge ausgeführt und dann nach der case-Anweisung (also hinter dem esac) fortgefahren. * In den Mustern sind Metazeichen (*, ?, []) erlaubt, im Selektor dagegen nicht

  • Das Muster * deckt sich mit jedem Selektor --> default-Ausgang. muss als letztes Muster in der case-Konstruktion stehen
  • Vor der Klammer können mehrere Muster, getrennt durch | stehen

Das Zeichen | bildet eine Oder-Bedingung:

case selector in
Muster1) Kommandofolge1 ;;
Muster2 | Muster3) Kommandofolge2 ;;
*) Kommandofolge3 ;;
esac
Beispiel 1

Automatische Bearbeitung von Quell- und Objekt-Dateien. Der Aufruf erfolgt mit 'compile Datei'

case1 in
*.s) as1 ;; # Assembler aufrufen
*.c) cc -c1 ;; # C-Compiler aufrufen
*.o) cc1 -o prog ;; # C-Compiler als Linker
*) echo "invalid parameter:1";;
esac
Beispiel 2

Menü mit interaktiver Eingabe

while : # Endlosschleife
do
tput clear # Schirm löschen und Menütext ausgeben
echo " +---------------------------------+"
echo " | 0 --> Ende |"
echo " | 1 --> Datum und Uhrzeit |"
echo " | 2 --> aktuelles Verzeichnis |"
echo " | 3 --> Inhaltsverzeichnis |"
echo " | 4 --> Mail |"
echo "+----------------------------------+"
echo "Eingabe: \c" # kein Zeilenvorschub
read ANTW
caseANTW in
0) kill -9 0 ;; # und tschuess
1) date ;;
2) pwd ;;
3) ls -CF ;;
4) elm ;;
*) echo "Falsche Eingabe!" ;;
esac
done

for-Anweisung

  • Diese Schleifenanweisung hat zwei Ausprägungen, mit einer Liste der zu bearbeitenden Elemente oder mit den Kommandozeilenparametern
  • Dieses Konstrukt ähnelt nur auf den ersten Blick seinen Pendants aus anderen Programmiersprachen
  • In anderen Sprachen wird die for-Schleife meistens dazu benutzt, eine Zählvariable über einen bestimmten Wertebereich iterieren zu lassen (for i = 1 to 100...next)
  • In der Shell dagegen wird die Laufvariable nicht mit aufeinander folgenden Zahlen belegt, sondern mit einzelnen Werten aus einer anzugebenden Liste
  • Wenn man eine Laufvariable benötigt, muss man dazu die while-Schleife einsetzen

Die Syntax der for-Schleife lautet wie folgt

for x [ in Liste ]
do

Befehle

done

Die Befehle werden ausgeführt, wobei der Variablen x nacheinander die Werte aus der Liste zugewiesen werden

  • Wie man sieht, ist die Angabe der Liste optional, wenn sie nicht angegeben wird, nimmt x der Reihe nach alle Werte aus@ (in dieser vordefinierten Variablen liegen die Aufrufparameter) an
  • Wenn die Ausführung eines Schleifendurchlaufs bzw. der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw. break benutzt werden

for-Schleife mit Liste

for selector in liste
do
Kommandofolge
done

Die Selektor-Variable wird nacheinander durch die Elemente der Liste ersetzt und die Schleife mit der Selektor-Variablen ausgeführt

Beispiele
for X in hans heinz karl luise do echoX done

Ausgabe
<syntaxhighlight lang="bash" highlight="1" line copy>
hans
heinz
karl
luise
for FILE in *.txt # drucke alle Textdateien
do # im aktuellen Verzeichnis
lprFILE
done
for XX inVAR # geht auch mit
do
echoXX
done

Durchsuche Kapitel zur Erstellung einer Wortliste (wie fgrep -f)

for item in(cat program_list) # cat: Datei ausgeben
do
echo "Pruefung der Kapitel auf"
echo "Referenzen zum Programmitem ..."
grep -c "$item.[co]" chap* # grep: nach Muster suchen
done


for-Schleife mit Parametern

for selector
do
Kommandofolge
done

Die Selektor-Variable wird nacheinander durch die Parameter1 bisn ersetzt und mit diesen Werten die Schleife durchlaufen. Es gibt also# Schleifendurchläufe

Beispiel

Die Prozedur 'makebak' erzeugt für die in der Parameterliste angegebenen Dateien eine .bak-Datei

for FF
do
cpFF{FF}.bak
done
#!/bin/sh
# Seitenweises Formatieren der Dateien, die auf der
# Befehlszeile angegeben wurden, und speichern des
# jeweiligen Ergebnisses

for file do
prfile >file.tmp # pr: Formatiert Textdateien
done
# Ermittle einen Ein-Wort-Titel aus jeder Datei und
# verwende ihn als neuen Dateinamen

for file do
name=`sed -n 's/NAME: //p'file`
# sed: Skriptsprache zur Textformatierung
mvfilename
# mv: Datei verschieben bzw.&nbsp;umbenennen
done

while

Die while-Schleife ist wieder ein Konstrukt, das einem aus vielen anderen Sprachen bekannt ist

Die kopfgesteuerte Schleife. Die Syntax der while-Schleife lautet wie folgt

while Bedingung
do

Befehle
done

Die Befehle werden so lange ausgeführt, wie die Bedingung erfüllt ist

Dabei wird die Bedingung vor der Ausführung der Befehle überprüft. Die Bedingung wird dabei üblicherweise, genau wie bei der if-Anweisung, mit dem Befehl test formuliert

Wenn die Ausführung eines Schleifendurchlaufs bzw. der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw. break benutzt werden

Beispiele
#!/bin/sh
# Zeilenweise Ausgabe aller Aufrufparameter

while [ -n "$1"]; do

echo1
shift # mit shift werden die Parameter nach
# Links geshiftet (aus2 wird1)
done


Zählschleife

In anderen Sprachen kann man mit der for-Schleife eine Zählvariable über einen bestimmten Wertebereich iterieren lassen (for i = 1 to 100...next)

Da das mit der for-Schleife der Shell nicht geht, ersetzt man die Funktion durch geschickte Anwendung der while-Schleife

#!/bin/sh
# Ausgabe der Zahlen von 1 bis 100
i=1
while [i -le 100 ]
do
echoi
i=`expri + 1`
done


Weitere Beispiele
#!/bin/sh

while who | grep "^root "
do sleep 30

done

echo Die Katze ist aus dem Haus, Zeit, dass die Mäuse tanzen!
Ergebniswert eines Kommandos

Als Bedingung kann nicht nur eine "klassische" Bedingung (test oder [ ]) sondern auch der Ergebniswert eines Kommandos oder einer Kommandofolge verwendet werden

while Bedingung
do
Kommandofolge
done

Solange der Bedingungsausdruck den Wert 'true' liefert, wird die Schleife ausgeführt

Warten auf eine Datei (beispielsweise vom Hintergrundprozess)
while [ ! -f foo ]
do
sleep 10 # Wichtig damit die Prozesslast nicht zu hoch wird
done

; Pausenfüller für das Terminal Abbruch mit DEL-Taste
while 
do
tput clear # BS löschen
echo -e "\n\n\n\n\n" # 5 Leerzeilen
banner(date '+ %T ') # Uhrzeit groß
sleep 10 # 10s Pause
done
Umbenennen von Dateien durch Anhängen eines Suffix
  1. Aufruf change suffix datei(en)

if [# -lt 2 ] ; then echo "Usage: `basename0` suffix file(s)" else SUFF=$1 # Suffix speichern shift while [# -ne 0 ] # solange Parameter da sind do mv1{1}.$SUFF # umbenennen shift done fi

Umbenennen von Dateien durch Anhängen eines Suffix Variante 2 mit for
# Aufruf change suffix datei(en)
if [# -lt 2 ] ; then
echo "Usage: `basename0` suffix file(s)"
else
SUFF=$1 # Suffix speichern
shift
for FILE
do
mvFILE{FILE}.$SUFF # umbenennen
shift
done
fi

until

Diese Anweisung ist identisch zu einer while-Schleife mit negierter Bedingung

Als Bedingung kann nicht nur eine "klassische" Bedingung (test oder [ ]) sondern auch der Ergebniswert eines Kommandos oder einer Kommandofolge verwendet werden

until Bedingung
do
Kommandofolge
done

Die Schleife wird so lange abgearbeitet, bis Bedingungsausdruck einen Wert ungleich Null liefert

Beispiel
# warten auf Datei foo
until [ -f foo ]
do
sleep 10
done
Warten auf einen Benutzer
# warten, bis sich der Benutzer hans eingeloggt hat
TT=`who | grep -c "hans"`
until [TT -gt 0 ]
do
sleep 10
TT=`who | grep -c "hans"`
done
# warten, bis sich der Benutzer hans eingeloggt hat
# Variante 2 - kuerzer
until [ `who | grep -c "hans"` -gt 0 ]
do
sleep 10
done

Die Befehle werden ausgeführt, bis die Bedingung erfüllt ist. Die Bedingung wird dabei üblicherweise, genau wie bei der if-Anweisung, mit dem Befehl test formuliert

Wenn die Ausführung eines Schleifendurchlaufs bzw. der ganzen Schleife abgebrochen werden soll, müssen die Kommandos continue bzw. break benutzt werden

Beispiel

Hier wird die Bedingung nicht per test, sondern mit dem Rückgabewert des Programms grep formuliert

#!/bin/sh
# Warten, bis sich der Administrator einloggt

until who | grep "root"; do
# who: Liste der Benutzer
# grep: Suchen nach Muster
sleep 30 # sleep: warten
done
echo "Der Meister ist anwesend"