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.4 Das Kommando tesdowntop

Wie Sie im Verlauf bereits festgestellt haben, scheint das test-Kommando das ultimative Werkzeug für viele Shellscripts zu sein. Und in der Tat wäre das Shell-Leben ohne dieses Kommando nur halb so einfach. Das test-Kommando wird überall dort eingebaut, wo ein Vergleich von Zeichenketten oder Zahlenwerten und eine Überprüfung von Zuständen einer Datei erforderlich sind. Da die if-Verzweigung eigentlich für Kommandos konzipiert wurde, ist es nicht so ohne weiteres möglich, einfach zwei Zeichenketten oder Zahlen mit einem if zu überprüfen. Würden Sie dies dennoch tun, würde die Shell entsprechende Zeichenketten oder Zahlenwerte als Befehl erkennen und versuchen, diesen auszuführen.

Damit Sie also solche Vergleiche durchführen können, benötigen Sie ein weiteres Kommando, das test-Kommando. Erst mit test ist es Ihnen möglich, verschiedene Ausdrücke zu formulieren und auszuwerten. Hier die Syntax des test-Kommandos:

if test Ausdruck
then
   # Ausdruck ist wahr, der Rückgabewert von test 0
   # hier die weiteren Kommandos bei erfolgreichem Ausdruck
fi

Das test-Kommando wird vorwiegend in seiner »symbolischen« Form mit den eckigen Klammern eingesetzt.

if [ Ausdruck ]
then
   # Ausdruck ist wahr, der Rückgabewert von test 0
   # hier die weiteren Kommandos bei erfolgreichem Ausdruck
fi

Hinweis   Bitte beachten Sie, dass der Befehl test Leerzeichen zwischen den einzelnen Ausdrücken erwartet. Dies gilt übrigens auch hinter jedem sich öffnenden [ und vor jedem schließenden ].


Dass bei einem korrekten Ausdruck wieder 0 zurückgegeben wird, liegt daran, dass test letztendlich auch nichts anderes als ein Kommando ist.


Rheinwerk Computing

4.4.1 Ganze Zahlen vergleichen  downtop

Um ganze Zahlen mit test zu vergleichen, stehen Ihnen folgende Operatoren zur Verfügung (siehe Tabelle 4.1):


Tabelle 4.1   Ganze Zahlen mit test vergleichen

Ausdruck Bedeutung Liefert wahr (0) zurück, wenn ...
[ var1 –eq var2 ] (eq = equal) var1 gleich var2 ist
[ var1 –ne var2 ] (ne = not equal) var1 ungleich var2 ist
[ var1 –lt var2 ] (lt = less than) var1 kleiner als var2 ist
[ var1 –gt var2 ] (gt = greater than) var1 größer als var2 ist
[ var1 –le var2 ] (le = less equal) var1 kleiner oder gleich var2 ist
[ var1 –ge var2 ] (ge = greater equal) var1 größer oder gleich var2 ist

Hier ein einfaches Script, das Ihnen die Zahlenvergleiche in der Praxis demonstriert:

# Demonstriert das test-Kommando mit Zahlenwerten
# Name: avalue
a=6; b=7
if [ $a -eq $b ]
then
   echo "\$a ($a) ist gleich mit \$b ($b)"
else
   echo "\$a ($a) ist nicht gleich mit \$b ($b)"
fi
if [ $a -gt $b ]
then
   echo "\$a ($a) ist größer als \$b ($b)"
elif [ $a -lt $b ]
then
   echo "\$a ($a) ist kleiner als \$b ($b)"
else
   echo "\$a ($a) ist gleich mit \$b ($b)"
fi
if [ $a -ne 5 ]
then
   echo "\$a ($a) ist ungleich 5"
fi
if [ 7 -eq $b ]
then
   echo "\$b ist gleich 7"
fi

Das Script bei der Ausführung:

you@host > ./avalue
$a (6) ist nicht gleich mit $b (7)
$a (6) ist kleiner als $b (7)
$a (6) ist ungleich 5
$b ist gleich 7

Dass hier tatsächlich numerische Zahlenvergleiche und keine String-Vergleiche stattfinden, ist den Ausdrücken –eq, –ne, –lt, –gt, –le und –ge zu verdanken. Steht einer dieser Ausdrücke zwischen zwei Zahlen, wandelt der Befehl test die Zeichenketten vorher noch in Zahlen um. Dabei ist das test-Kommando sehr »intelligent« und erkennt selbst folgende Werte als Zahlen an:

you@host > a="00001"; b=1
you@host > [ $a -eq $b ]
you@host > echo $?
0
you@host > a="        1"; b=1
you@host > [ $a -eq $b ]
you@host > echo $?
0

Hier wurde auch die Zeichenkette "00001" und " 1" von test in eine numerische 1 umgewandelt.

Argumente aus der Kommandozeile überprüfen

Eine fast immer verwendete Aktion des test-Kommandos ist das Überprüfen, ob die richtige Anzahl von Argumenten in der Kommandozeile eingegeben wurde. Die Anzahl der Argumente finden Sie in der Variablen $# – mit dem test-Kommando können Sie jetzt entsprechend reagieren.

# Überprüft die richtige Anzahl von Argumenten
# aus der Kommandozeile
# Name: atestarg
if [ $# -ne 2 ]
then
   echo "Hier sind mindestens 2 Argumente erforderlich"
   echo "usage: $0 arg1 arg2 ... [arg_n]"
   exit 1
else
   echo "Erforderliche Anzahl Argumente erhalten"
fi

Das Script bei der Ausführung:

you@host > ./atestarg
Hier sind mindestens 2 Argumente erforderlich
usage: atestarg arg1 arg2 ... [arg_n]
you@host > ./atestarg Hallo Welt
Erforderliche Anzahl Argumente erhalten

Rheinwerk Computing

4.4.2 Ganze Zahlen vergleichen mit let (Bash und Korn-Shell only)  downtop

In der Bash und der Korn-Shell steht Ihnen noch eine weitere Alternative zum Vergleichen von Zahlen zur Verfügung. Hier kommen auch die programmiertypischen Operatoren für den Vergleich zum Einsatz (siehe Tabelle 4.2).


Tabelle 4.2   Ganze Zahlen mit test vergleichen (Bash und Korn-Shell)

Ausdruck Operator Liefert wahr (0) zurück, wenn ...
(( var1 == var2 )) == var1 gleich var2 ist
(( var1 != var2 )) != var1 ungleich var2 ist
(( var1 < var2 )) < var1 kleiner als var2 ist
(( var1 > var2 )) > var1 größer als var2 ist
(( var1 >= var2 )) >= var1 größer oder gleich var2 ist
(( var1 <= var2 )) <= var1 kleiner oder gleich var2 ist

Wer sich vielleicht noch an den let-Abschnitt erinnert, dem dürfte auffallen, was wir hier haben – richtig, bei der doppelten Klammerung (( ... )) handelt es sich um nichts anderes als um eine symbolische Form für das let-Kommando, welches Sie bereits bei den Variablen mit arithmetischen Ausdrücken verwendet haben. Natürlich können Sie hierbei auch anstatt der doppelten Klammerung das Kommando let verwenden. So kann beispielsweise statt

if (( $a > $b ))

auch let verwendet werden:

if let "$a > $b"

Im Gegensatz zur Verwendung von –eq, –ne usw. sind die Leerzeichen bei den Zahlenvergleichen hier nicht von Bedeutung und können bei Bedarf unleserlich zusammengequetscht werden ;-). Des Weiteren kann, wie Sie von let vielleicht noch wissen, das $-Zeichen vor den Variablen beim Vergleich in doppelter Klammerung entfallen.

Wollen Sie bspw. aus dem Listing »atestarg« den Test, ob die richtige Anzahl von Argumenten in der Kommandozeile eingegeben wurde, umschreiben auf die alternative Schreibweise der Bash und Korn-Shell, so müssen Sie nur die Zeile

if [ $# -ne 2 ]

umschreiben in

if (( $# != 2 ))

Rheinwerk Computing

4.4.3 Zeichenketten vergleichen  downtop

Das Vergleichen von Zeichenketten mit test funktioniert ähnlich wie bei Zahlenwerten. Hierbei übergeben Sie dem Kommando test eine Zeichenkette, einen Operanden und eine weitere Zeichenkette. Auch hier müssen Sie wieder jeweils (mindestens) ein Leerzeichen dazwischen einschieben. In Tabelle 4.3 sind die Operatoren zum Vergleichen von Zeichenketten aufgelistet:


Tabelle 4.3   Zeichenketten vergleichen

Ausdruck Operator Liefert wahr (0) zurück, wenn ...
[ "$var1" = "$var2" ] = var1 gleich var2 ist
[ "$var1" != "$var2" ] != var1 ungleich var2 ist
[ –z "$var" ] –z var leer ist
[ –n "$var" ] –n var nicht leer ist


Hinweis   Auch wenn es nicht vorgeschrieben ist, sollten Sie bei einem test mit Zeichenketten diese immer zwischen zwei doppelte Anführungszeichen setzen. Dies hilft Ihnen zu vermeiden, dass beim Vergleich einer Variable, die nicht existiert oder kein "" enthält, Fehler auftreten.


Auch hierzu ein einfaches Shellscript, das verschiedene Vergleiche von Zeichenketten durchführt.

# Demonstriert einfache Zeichenkettenvergleiche
# ateststring
name1=juergen
name2=jonathan
if [ $# -lt 1 ]
then
   echo "Hier ist mindestens ein Argument erforderlich"
   echo "usage: $0 Zeichenkette"
   exit 1
fi
if [ "$1" = "$name1" ]
then
   echo "Hallo juergen"
elif [ "$1" = "$name2" ]
then
   echo "Hallo jonathan"
else
   echo "Hier wurde weder $name1 noch $name2 verwendet"
fi
if [ -n "$2" ]
then
   echo "Hier wurde auch ein zweites Argument verwendet ($2)"
else
   echo "Hier wurde kein zweites Argument verwendet"
fi
if [ -z "$name3" ]
then
   echo "Der String \$name3 ist leer oder existiert nicht"
elif [ "$name3" != "you" ]
then
   echo "Bei \$name3 handelt es sich nicht um \"you\""
else
   echo "Hier ist doch \"you\" gemeint"
fi

Das Script bei der Ausführung:

you@host > ./ateststring
Hier ist mindestens ein Argument erforderlich
usage: ./ateststring Zeichenkette
you@host > ./ateststring test
Hier wurde weder juergen noch jonathan verwendet
Hier wurde kein zweites Argument verwendet
Der String $name3 ist leer oder existiert nicht
you@host > ./ateststring juergen
Hallo juergen
Hier wurde kein zweites Argument verwendet
Der String $name3 ist leer oder existiert nicht
you@host > ./ateststring juergen wolf
Hallo juergen
Hier wurde auch ein zweites Argument verwendet (wolf)
Der String $name3 ist leer oder existiert nicht
you@host > name3=wolf
you@host > export name3
you@host > ./ateststring jonathan wolf
Hallo jonathan
Hier wurde auch ein zweites Argument verwendet (wolf)
Bei $name3 handelt es sich nicht um "you"
you@host > export name3=you
you@host > ./ateststring jonathan wolf
Hallo jonathan
Hier wurde auch ein zweites Argument verwendet (wolf)
Hier ist doch "you" gemeint

Wer jetzt immer noch denkt, man könne mit den bisherigen Mitteln noch kein vernünftiges Shellscript schreiben, für den soll hier ein einfaches Backup-Script geschrieben werden. Das folgende Script soll Ihnen zwei Möglichkeiten bieten. Zum einen eine Eingabe wie:

you@host > ./abackup1 save $HOME/Shellbuch

Hiermit soll der komplette Inhalt vom Verzeichnis $HOME/Shellbuch mittels tar archiviert werden (mitsamt den Meldungen des kompletten Verzeichnisbaums). Das Backup soll in einem extra erstellen Verzeichnis mit einem extra erstellten Namen (im Beispiel einfach TagMonatJahr.tar, bspw. 21Feb2005.tar) erstellt werden (natürlich komprimiert).

Auf der anderen Seite soll es selbstverständlich auch möglich sein, den Inhalt dieser Meldungen, der archivierten Backup-Datei, zu lesen, was gerade bei vielen Backup-Dateien auf der Platte unverzichtbar ist. Dies soll mit einem Aufruf wie

you@host > ./abackup1 read $HOME/backup/21Feb2005.tar

erreicht werden. Mit grep hinter einer Pipe können Sie nun nach einer bestimmten Datei im Archiv suchen. Dies könnte man natürlich auch im Script extra einbauen. Aber der Umfang soll hier nicht ins Unermessliche wachsen. Hier ein einfaches, aber anspruchsvolles Backup-Script:

# Ein einfaches Backup-Script
# Name: abackup1
# Beispiel: ./abackup1 save Verzeichnis
# Beispiel: ./abackup1 read (backupfile).tar
BACKUPDIR=$HOME/backup
DIR=$2
if [ $# != 2 ]
then
   echo "Hier sind 2 Argumente erforderlich"
   echo "usage: $0 Option Verzeichnis/Backupfile"
   echo
   echo "Mögliche Angaben für Option:"
   echo "save = Führt Backup vom kompletten Verzeichnis durch"
   echo "       Verzeichnis wird als zweites Argument angegeben"
   echo "read = Liest den Inhalt eines Backupfiles"
   echo "       Backupfile wird als zweites Argument angegeben"
   exit 1
fi
# Falls Verzeichnis für Backup nicht existiert ...
if ls $BACKUPDIR > /dev/null
then
   echo "Backup-Verzeichnis ($BACKUPDIR) existiert"
elif mkdir $BACKUPDIR > /dev/null
then
   echo "Backup-Verzeichnis angelegt ($BACKUPDIR)"
else
   echo "Konnte kein Backup-Verzeichnis anlegen"
   exit 1
fi
# Wurde save oder read als erstes Argument verwendet ...
if [ "$1" = "save" ]
then
   set `date`
   BACKUPFILE="$3$2$6"
   if tar czvf ${BACKUPDIR}/${BACKUPFILE}.tar $DIR
   then
      echo "Backup für $DIR erfolgreich in $BACKUPDIR angelegt"
      echo "Backup-Name : ${BACKUPFILE}.tar"
   else
      echo "Backup wurde nicht durchgeführt !!!"
   fi
elif [ "$1" = "read" ]
then
   echo "Inhalt von $DIR : "
   tar tzf $DIR
else
   echo "Falsche Scriptausführung!!!"
   echo "usage: $0 option Verzeichnis/Backupfile"
   echo
   echo "Mögliche Angaben für Option:"
   echo "save = Führt ein Backup eines kompletten Verzeichnisses durch"
   echo "       Verzeichnis wird als zweites Argument angegeben"
   echo "read = Liest den Inhalt eines Backupfiles"
   echo "       Backupfile wird als zweites Argument angegeben"
fi

Das Script bei der Ausführung:

you@host > ./abackup1 save $HOME/Shellbuch
ls: /home/you/backup: Datei oder Verzeichnis nicht gefunden
Backup-Verzeichnis angelegt (/home/you/backup)
tar: Entferne führende `/' von Archivnamen.
home/you/Shellbuch/
home/you/Shellbuch/Planung_und_Bewerbung/
home/you/Shellbuch/Planung_und_Bewerbung/shellprogrammierung.doc
home/you/Shellbuch/Planung_und_Bewerbung/shellprogrammierung.sxw
home/you/Shellbuch/kap004.txt
home/you/Shellbuch/Kap003.txt~
home/you/Shellbuch/kap004.txt~
...
Backup für /home/you/Shellbuch erfolgreich in /home/you/backup 
angelegt
Backup-Name : 21Feb2005.tar
you@host > ./abackup1 read $HOME/backup/21Feb2005.tar | \
> grep Kap002
home/tot/Shellbuch/Kap002.doc
home/tot/Shellbuch/Kap002.sxw
you@host > ./abackup1 read $HOME/backup/21Feb2005.tar | wc -l
50

Hier wurde ein Backup vom kompletten Verzeichnis $HOME/Shellbuch durchgeführt. Anschließend wurde mit der Option read und grep nach »Kap002« gesucht, welches hier in zweifacher Ausführung vorhanden ist. Ebenso einfach können Sie hiermit die Anzahl von Dateien in einem Archiv (hier mit wc –l) ermitteln.


Rheinwerk Computing

4.4.4 Zeichenketten vergleichen (Bash und Korn-Shell only)  toptop

In der Bash und der Korn-Shell stehen Ihnen noch weitere alternative Möglichkeit zur Verfügung, um Zeichenketten zu vergleichen (siehe Tabelle 4.4). Besonders interessant erscheint mir in diesem Zusammenhang, dass hiermit jetzt auch echte Mustervergleiche möglich sind.


Tabelle 4.4   Zeichenketten vergleichen (Bash und Korn-Shell)

Ausdruck Operator Liefert wahr (0) zurück, wenn ...
[[ "$var1" == "$var2" ]] == var1 gleich var2 ist
[[ "$var1" != "$var2" ]] != var1 ungleich var2 ist
[[ –z "$var" ]] –z var leer ist
[[ –n "$var" ]] –n var nicht leer ist
[[ "$var1" > "$var2" ]] > var1 alphabetisch größer als var2 ist
[[ "$var1" < "$var2" ]] < var1 alphabetisch kleiner als var2 ist
[[ "$var" == pattern ]] == var entspricht dem Muster pattern
[[ "$var" != pattern ]] != var entspricht nicht dem Muster-Pattern

Das wirklich sehr interessante Feature bei den Vergleichen von Zeichenketten in Bash und Korn-Shell ist die Möglichkeit, Muster beim Vergleich zu verwenden. Hierbei gilt es zu beachten, dass sich das Muster auf der rechten Seite befindet und nicht zwischen Anführungsstrichen stehen darf. Zur Verwendung von Mustern stehen Ihnen wieder die Metazeichen *, ? und [ ] zur Verfügung, deren Bedeutung und Verwendung Sie bereits in Abschnitt 1.10.6 kennen gelernt haben. Natürlich können Sie auch die Konstruktionen für alternative Muster nutzen, welche Sie in Abschnitt 1.10.8 verwendet haben. Hier ein Beispiel mit einfachen Mustervergleichen:

# Demonstriert erweiterte Zeichenkettenvergleiche
# ateststring2
if [ $# -lt 1 ]
then
   echo "Hier ist mindestens ein Argument erforderlich"
   echo "usage: $0 Zeichenkette"
   exit 1
fi
if [[ "$1" = *ist* ]]
then
   echo "$1 enthält die Textfolge \"ist\""
elif [[ "$1" = ?art ]]
then
   echo "$1 enthält die Textfolge \"art\""
elif [[ "$1" = kap[0–9] ]]
then
   echo "$1 enthält die Textfolge \"kap\""
else
   echo "Erfolgloser Mustervergleich"
fi

Das Script bei der Ausführung:

you@host > ./ateststring2 Bauart
Erfolgloser Mustervergleich
you@host > ./ateststring2 zart
zart enthält die Textfolge "art"
you@host > ./ateststring2 kap7
kap7 enthält die Textfolge "kap"
you@host > ./ateststring2 kapa
Erfolgloser Mustervergleich
you@host > ./ateststring2 Mistgabel
Mistgabel enthält die Textfolge "ist"

Eine weitere interessante Erneuerung ist der Vergleich auf größer bzw. kleiner als. Hiermit werden Zeichenketten alphabetisch in lexikografischer Anordnung verglichen. Hierzu ein Script:

# Demonstriert erweiterte Zeichenkettenvergleiche
# ateststring3
var1=aaa
var2=aab
var3=aaaa
var4=b
if [[ "$var1" > "$var2" ]]
then
   echo "$var1 ist größer als $var2"
else
   echo "$var1 ist kleiner als $var2"
fi
if [[ "$var2" < "$var3" ]]
then
   echo "$var2 ist kleiner als $var3"
else
   echo "$var2 ist größer als $var3"
fi
if [[ "$var3" < "$var4" ]]
then
   echo "$var3 ist kleiner als $var4"
else
   echo "$var3 ist größer als $var4"
fi

Das Script bei der Ausführung:

you@host > ./ateststring3
aaa ist kleiner als aab
aab ist größer als aaaa
aaaa ist kleiner als b

An diesem Script können Sie sehr gut erkennen, dass hier nicht die Länge der Zeichenkette zwischen dem größer bzw. kleiner entscheidet, sondern das Zeichen, womit die Zeichenkette beginnt. Somit ist laut Alphabet das Zeichen a kleiner als das Zeichen b. Beginnen beide Zeichenketten mit dem Buchstaben a, wird das nächste Zeichen verglichen – eben so, wie Sie dies von einem Lexikon her kennen.



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.


[Rheinwerk Computing]

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