Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
Shell-Programmierung von Jürgen Wolf
Einführung, Praxis, Referenz
Buch: Shell-Programmierung

Shell-Programmierung
782 S., mit CD, 44,90 Euro
Rheinwerk Computing
ISBN 3-89842-683-1
gp Kapitel 4 Kontrollstrukturen
  gp 4.1 Bedingte Anweisung mit if
    gp 4.1.1 Kommandos testen mit if
    gp 4.1.2 Kommandoverkettung über Pipes mit if
  gp 4.2 Die else-Alternative für eine if-Verzweigung
  gp 4.3 Mehrfache Alternative mit elif
  gp 4.4 Das Kommando test
    gp 4.4.1 Ganze Zahlen vergleichen
    gp 4.4.2 Ganze Zahlen vergleichen mit let (Bash und Korn-Shell only)
    gp 4.4.3 Zeichenketten vergleichen
    gp 4.4.4 Zeichenketten vergleichen (Bash und Korn-Shell only)
  gp 4.5 Status von Dateien erfragen
  gp 4.6 Logische Verknüpfung von Ausdrücken
    gp 4.6.1 Negationsoperator !
    gp 4.6.2 Die UND-Verknüpfung (-a und &&)
    gp 4.6.3 Die ODER-Verknüpfung (-o und ||)
    gp 4.6.4 Klammerung und mehrere logische Verknüpfungen
  gp 4.7 Short Circuit-Tests – ergebnisabhängige Befehlsausführung
  gp 4.8 Die Anweisung case
    gp 4.8.1 Alternative Vergleichsmuster
    gp 4.8.2 case und Wildcards
    gp 4.8.3 case und Optionen
  gp 4.9 Schleifen
  gp 4.10 for-Schleife
    gp 4.10.1 Argumente bearbeiten mit for
    gp 4.10.2 for und die Dateinamen-Substitution
    gp 4.10.3 for und die Kommando-Substitution
    gp 4.10.4 for und Array (Bash und Korn Shell only)
    gp 4.10.5 for-Schleife mit Schleifenzähler (Bash only)
  gp 4.11 Die while-Schleife
  gp 4.12 Die until-Schleife
  gp 4.13 Kontrollierte Sprünge
    gp 4.13.1 Der Befehl continue
    gp 4.13.2 Der Befehl break
  gp 4.14 Endlosschleifen


Rheinwerk Computing

4.10 for-Schleifdowntop

Die for-Schleife gehört zu der Familie der Aufzählschleifen. Damit wird eine Befehlsfolge für Wörter in einer angegebenen Liste ausgeführt. Das heißt, die for-Schleife benötigt eine Liste von Parametern. Die Anzahl der Wörter in dieser Liste bestimmt dann, wie oft die Schleife ausgeführt bzw. durchlaufen wird. Hier zunächst die Syntax der for-Schleife:

for var in liste_von_parameter
do
   kommando
   ...
   kommando
done

Die Funktionsweise von for ist folgende: Vor jedem Eintritt in die Schleife wird das nächste Wort der Parameterliste in die Variable »var« gelegt. Die Liste der Parameter hinter dem Schlüsselwort in besteht aus Wörtern, die jeweils von mindestens einem Leerzeichen (bzw. auch abhängig von der Variablen IFS) getrennt sein müssen. Dies kann bspw. so aussehen:

for var in wort1 wort2 wort3
do
...
done

Somit würde beim ersten Schleifendurchlauf der Wert von »wort1« in die Variable »var« übertragen. Jetzt werden die Kommandos zwischen den Schlüsselworten do und done ausgeführt. Wurden alle Kommandos abgearbeitet, beginnt der nächste Schleifendurchlauf, bei dem jetzt »wort2« in die Variable »var« übertragen wird. Dieser Vorgang wird so lange wiederholt, bis alle Elemente der Parameterliste abgearbeitet wurden. Anschließend wird mit der Ausführung hinter dem Schlüsselwort done fortgefahren (siehe Abbildung 4.11).


Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 4.11   Die for-Schleife



Rheinwerk Computing

4.10.1 Argumente bearbeiten mit for  downtop

Wenn Sie sich die for-Schleife mit der Parameterliste ansehen, dürften Sie wohl gleich auf die Auswertung der Argumente in der Kommandozeile kommen. for scheint wie geschaffen, diese Argumente zu verarbeiten. Hierzu müssen Sie für die Parameterliste lediglich die Variable $@ verwenden. Das folgende Script überprüft alle Dateien, die Sie in der Kommandozeile mit angeben auf Ihren Typ.

# Demonstriert die Verwendung von for mit Argumenten
# afor1
for datei in "$@"
do
   [ -f $datei ] && echo "$datei: Reguläre Datei"
   [ -d $datei ] && echo "$datei: Verzeichnis"
   [ -b $datei ] && echo "$datei: Gerätedatei(block special)"
   [ -c $datei ] && echo "$datei: Gerätedatei(character special)"
   [ -t $datei ] && echo "$datei: serielles Terminal"
   [ ! -e $datei ] && echo "$datei: existiert nicht"
done

Das Script bei der Ausführung:

you@host > ./afor1 Shellbuch backup afor1 /dev/tty \
> /dev/cdrom gibtsnicht
Shellbuch: Verzeichnis
backup: Verzeichnis
afor1: Reguläre Datei
/dev/tty: Gerätedatei (character special)
/dev/cdrom: Gerätedatei (block special)
gibtsnicht: existiert nicht

Zwar könnten Sie in Ihrem Script auch die Positionsparameter $1 bis $n verwenden, aber Sie sollten dies wenn möglich vermeiden und stattdessen die Variable $@ benutzen. Damit können Sie sichergehen, dass kein Argument aus der Kommandozeile vergessen wurde.

Eine Besonderheit bezüglich der Variablen $@ in der for-Schleife gibt es dann doch noch. Lassen Sie den Zusatz in "$@" weg, setzt die for-Schleife diesen automatisch ein:

# Demonstriert die Verwendung von for mit Argumenten
# afor1
for datei
do
   [ -f $datei ] && echo "$datei: Reguläre Datei"
   [ -d $datei ] && echo "$datei: Verzeichnis"
   [ -b $datei ] && echo "$datei: Gerätedatei(block special)"
   [ -c $datei ] && echo "$datei: Gerätedatei(character special)"
   [ -t $datei ] && echo "$datei: serielles Terminal"
   [ ! -e $datei ] && echo "$datei: existiert nicht"
done

Rheinwerk Computing

4.10.2 for und die Dateinamen-Substitution  downtop

Das Generieren von Dateinamen mit den Metazeichen *, ? und [] kennen Sie ja bereits zur Genüge. Dieser Ersetzungsmechanismus wird standardmäßig von der Shell ausgeführt, sobald ein solches Sonderzeichen erkannt wird. Diese Dateinamen-Substitution können Sie auch in der for-Schleife verwenden. Dadurch wird eine Liste von Dateinamen für die Parameterliste der for-Schleife erzeugt. Die Frage, wie Sie ein ganzes Verzeichnis auslesen können, wird Ihnen hiermit so beantwortet:

# Demonstriert die Verwendung von for und der Datei-Substitution
# afor2
# Gibt das komplette aktuelle Arbeitsverzeichnis aus
for datei in *
do
   echo $datei
done

Wenn Sie das Script ausführen, wird das komplette aktuelle Arbeitsverzeichnis ausgegeben. Selbstverständlich können Sie das Ganze auch einschränken. Wollen Sie z. B. nur alle Dateien mit der Endung ».txt« ausgeben, können Sie folgendermaßen vorgehen:

# Demonstriert die Verwendung von for und der Datei-Substitution
# afor3
# Gibt alle Textdateien des aktuellen Arbeitsverzeichnisses aus
for datei in *.txt
do
   echo $datei
   [ -r $datei ] && echo "... ist lesbar"
   [ -w $datei ] && echo "... ist schreibbar"
done

Sie können alle Metazeichen *, ? und [] verwenden, wie Sie dies von der Shell her kennen. Einige Beispiele:

# Nur Dateien mit der Endung *.txt und *.c berücksichtigen
for datei in *.txt *.c
# Nur die Dateien log1.txt log2.txt ... log9.txt berücksichtigen
for datei in log[1–9].txt
# Nur versteckte Dateien beachten (beginnend mit einem Punkt)
for datei in * .*

Kann in der for-Schleife ein Suchmuster nicht aufgelöst werden, führt das Script gewöhnlich keine Aktion durch. Solch einen Fall sollte man aber auch berücksichtigen, sofern Ihr Script benutzerfreundlich sein soll. Hierzu bietet sich eine case-Anweisung an, mit der Sie überprüfen, ob die entsprechende Variable (die in for ihren Wert von der Parameterliste erhält) auf das gewünschte Muster (Parameterliste) passt. Ganz klar, dass auch hierbei das Wildcard-Zeichen * verwendet wird.

# Demonstriert die Verwendung von for und der Datei-Substitution
# afor4
# Bei erfolgloser Suche soll ein entsprechender Hinweis
# ausgegeben werden
for datei in *.jpg
do
   case "$datei" in
      *.jpg)   echo "Keine Datei zum Muster *.jpg vorhanden" ;;
      *)       echo $datei ;;
   esac
done

Das Script bei der Ausführung:

you@host > ./afor4
Keine Datei zum Muster *.jpg vorhanden

Die case-Verzweigung *.jpg) wird immer dann ausgeführt, wenn kein Suchmuster aufgelöst werden konnte. Ansonsten wird die Ausführung bei *) weitergeführt, was hier wieder eine simple Ausgabe des Dateinamens darstellt.


Rheinwerk Computing

4.10.3 for und die Kommando-Substitution  downtop

Mittlerweile dürften Sie schon überzeugt sein vom mächtigen Feature der for-Schleife. Ein weiteres unverzichtbares Mittel der Shell-Programmierung aber erhalten Sie aus der for-Schleife, die ihre Parameter aus einer Kommando-Substitution erhält. Dazu könnten Sie die Ausgabe von jedem beliebigen Kommando für die Parameterliste verwenden. Allerdings setzt die Verwendung der Kommando-Substitution immer gute Kenntnisse der entsprechenden Kommandos voraus – insbesondere über deren Ausgabe.

Hier ein einfaches Beispiel, bei dem Sie mit dem Kommando find alle Grafikdateien im HOME-Verzeichnis mit der Endung ».png« suchen und in ein separat dafür angelegtes Verzeichnis kopieren. Dabei sollen auch die Namen der Dateien entsprechend neu durchnummeriert werden.

# Demonstriert die Verwendung von for und der Kommando-Substitution
# afor5
count=1
DIR=$HOME/backup_png
# Verzeichnis anlegen
mkdir $DIR 2>/dev/null
# Überprüfen, ob erfolgreich angelegt oder überhaupt
# vorhanden, ansonsten Ende
[ ! -e $DIR ] && exit 1
for datei in `find $HOME -name "*.png" -print 2>/dev/null`
do
   #  Wenn Leserecht vorhanden, können wir die Datei kopieren
   if [ -r $datei ]
   then
      # PNG-Datei ins entsprechende Verzeichnis kopieren
      # Als Namen bild1.png, bild2.png ... bildn.png verwenden
      cp $datei $DIR/bild${count}.png
      # Zähler um eins erhöhen
      count=`expr $count + 1`
   fi
done
echo "$count Bilder erfolgreich nach $DIR kopiert"

Das Script bei der Ausführung:

you@host > ./afor5
388 Bilder erfolgreich nach /home/tot/backup_png kopiert
you@host > ls backup_png
bild100.png  bild15.png   bild218.png  bild277.png  bild335.png
bild101.png  bild160.png  bild219.png  bild278.png  bild336.png
...

Da die Parameterliste der for-Schleife von der Variablen IFS abhängt, können Sie standardmäßig hierbei auch zeilenweise mit dem Kommando cat etwas einlesen und weiterverarbeiten – denn in der Variable IFS finden Sie auch das Newline-Zeichen wieder. Es sei bspw. folgende Datei namens .userlist mit einer Auflistung aller User, die bisher auf dem System registriert sind, gegeben:

you@host > cat .userlist
tot
you
rot
john
root
martin

Wollen Sie jetzt an alle User, die hier aufgelistet und natürlich im Augenblick eingeloggt sind, eine Nachricht senden, gehen Sie wie folgt vor:

# Demonstriert die Verwendung von for und
# der Kommando-Substitution
# afor6
# Komplette Argumentenliste für News an andere User verwenden
NEU="$*"
for user in `cat .userlist`
do
   if who | grep ^$user > /dev/null
   then
      echo $NEU | write $user
      echo "Verschickt an $user"
   fi
done

Das Script bei der Ausführung:

you@host > ./afor6 Tolle Neuigkeiten: Der Chef ist weg!
Verschickt an tot
Verschickt an martin

Im Augenblick scheinen hierbei die User »tot« und »martin« eingeloggt zu sein. Bei diesen sollte nun in der Konsole Folgendes ausgegeben werden:

tot@host >
Message from you@host on pts/40 at 04:33
Tolle Neuigkeiten: Der Chef ist weg!
EOF
tot@host >

Wenn beim anderen User keine Ausgabe erscheint, kann es sein, dass er die entsprechende Option abgeschaltet hat. Damit andere User Ihnen mit dem write-Kommando Nachrichten zukommen lassen können, müssen Sie dies mit

tot@host > mesg y

einschalten. Mit mesg n schalten Sie es wieder ab.

Variablen-Interpolation

Häufig werden bei der Kommando-Substitution die Kommandos recht lang und kompliziert, weshalb sich hierfür eine Variablen-Interpolation besser eignen würde. Also, anstatt die Kommando-Substitution in die Parameterliste von for zu quetschen, können Sie den Wert der Kommando-Substitution auch in einer Variablen abspeichern und diese Variable an for übergeben. Um bei einem Beispiel von eben zu bleiben (afor5), würde man mit

for datei in `find $HOME -name "*.png" -print 2>/dev/null`
do
   ...
done

dasselbe erreichen wie mit der folgenden Variablen-Interpolation:

PNG=`find $HOME -name "*.png" -print 2>/dev/null`
for datei in $PNG
do
   ...
done

Nur hat man hier ganz klar den Vorteil, dass dies übersichtlicher ist als die »direkte« Version.


Rheinwerk Computing

4.10.4 for und Array (Bash und Korn Shell only)  downtop

Selbstverständlich eignet sich die for-Schleife hervorragend für die Arrays. Die Parameterliste lässt sich relativ einfach mit ${array[*]} realisieren.

# Demonstriert die Verwendung von for und der Arrays
# afor7
# Liste von Werten in einem Array speichern
# Version: Korn-Shell (auskommentiert)
#set -A array 1 2 3 4 5 6 7 8 9
# Version: bash
array=( 1 2 3 4 5 6 7 8 9 )
# Alle Elemente im Array durchlaufen
for value in ${array[*]}
do
   echo $value
done

Das Script bei der Ausführung:

you@host > ./afor7
1
2
3
4
5
6
7
8
9

Rheinwerk Computing

4.10.5 for-Schleife mit Schleifenzähler (Bash only)  toptop

Ab Version 2.0.4 wurde der Bash eine zweite Form der for-Schleife spendiert. Die Syntax ist hierbei an die der Programmiersprache C angelehnt.

for (( var=Anfangswert ; Bedingung ; Zähler ))
do
   kommando1
   ...
   kommanodn
done

Diese Form der for-Schleife arbeitet mit einem Schleifenzähler. Bei den einzelnen Parametern handelt es sich um arithmetische Substitutionen. Der erste Wert, hier »var«, wird gewöhnlich für die Zuweisung eines Anfangswertes an eine Schleifenvariable verwendet. Der Anfangswert (»var«) wird hierbei nur einmal beim Eintritt in die Schleife ausgewertet. Die Bedingung dient als Abbruchbedingung und der Zähler wird verwendet, um die Schleifenvariable zu erhöhen oder zu verringern. Die Bedingung wird vor jedem neuen Schleifendurchlauf überprüft. Der Zähler hingegen wird nach jedem Schleifendurchlauf verändert. Den Zähler können Sie folgendermaßen ausdrücken (siehe Tabelle 4.12):


Tabelle 4.12   Zähler einer Schleifenvariablen verändern

Zähler verändern Bedeutung
var++ Den Wert nach jedem Schleifendurchlauf um 1 erhöhen (inkrementieren)
var–– Den Wert nach jedem Schleifendurchlauf um 1 verringern (dekrementieren)
((var=var+n)) Den Wert nach jedem Schleifendurchlauf um n erhöhen
((var=var–n)) Den Wert nach jedem Schleifendurchlauf um n verringern

Sie können auch andere arithmetische Ausdrücke verwenden. So toll sich das anhört, sollten Sie dennoch bedenken, dass dieses for-Konstrukt nur der Bash zur Verfügung steht. Hier einige Beispiele, wie Sie diese Form der for-Schleife in der Praxis einsetzen können:

# Demonstriert die Verwendung einer
# zweiten for-Form (Bash only)
# afor8
[ $# -lt 1 ] && echo "Mindestens ein Argument" && exit 1
# Liste von Argumenten in einem Array speichern
array=( $* )
for((i=0; i<$#; i++))
do
   echo "Argument $i ist ${array[$i]}"
done
# Countdown
for((i=5; i>0; i--))
do
   echo $i
   sleep 1   # Eine Sekunde anhalten
done
echo "...go"
# Auch andere arithmetische Ausdrücke als Zähler möglich
for((i=100; i>0; ((i=i/2)) ))
do
   echo $i
done

Das Script bei der Ausführung:

you@host > ./afor8 hallo welt wie gehts
Argument 0 ist hallo
Argument 1 ist welt
Argument 2 ist wie
Argument 3 ist gehts
5
4
3
2
1
...go
100
50
25
12
6
3
1


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
 << zurück
  
  Zum Katalog
Zum Katalog: Shell-Programmierung
Shell-Programmierung
bestellen
 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-Server






 Linux-Server


Zum Katalog: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Katalog: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Katalog: Linux Handbuch






 Linux Handbuch


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2005
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de