Listing 2
#!/bin/bash DIRS="`cat $1`" # DIRS = Inhalt der Datei im ersten Argument shift # entfernt das erste Argument aus der Liste OUTFILE="$(date +%y%m%d)" # erstellt einen Archivnamen mit Datum tar czf /tmp/$OUTFILE.tgz $DIRS $@ >/dev/null
Das Skript verwendet die Variablen DIRS und OUTFILE. Gemäß unausgesprochener Konvention und für eine bessere Übersicht verwenden Sie am besten Großbuchstaben in den Variablennamen – zwingend erforderlich ist das aber nicht. Mit der ersten Anweisung speichert das Skript den Inhalt der im ersten Argument angegebenen Datei. Durch das Setzen der Backticks fügen Sie statt des Cat-Befehls selbst dessen Ausgabe ein.
Das klappt mit jedem Befehl, den Sie zwischen die Backticks setzen. Auf diese Weise führt die Shell diesen zuerst aus und setzt die Ausgabe an dieser Stelle ein. Steht dieses Konstrukt innerhalb einer Anweisung, übernimmt diese anschließend die Ausgabe.
Im Beispiel gibt der Befehl cat den Inhalt der als erstes Argument zum Skript angegebenen Datei – also der Verzeichnisliste – aus und fügt diese innerhalb der doppelten Anführungszeichen in die Zuordnung für die Variable DIRS ein. Zeilenumbrüche in der Datei der Verzeichnisliste spielen dabei keine Rolle, die Shell wandelt diese in Leerzeichen um.
Nach dem Einlesen der Datei und dem Abarbeiten des ersten Arguments entfernt die Anweisung shift den Dateinamen aus der Liste. Die neue Liste der Argumente enthält zudem Verzeichnisse, sofern Sie diese zuvor in der Kommandozeile angegeben haben, und $@ expandiert wieder zur gewünschten Liste: Das Skript ersetzt die Variable durch die Verzeichnisnamen. Der Mechanismus ermöglicht es also, eine feste Liste von Elementen zum Archivieren im Skript zu speichern und – falls nötig – weitere Elemente als Parameter mit einzubeziehen.
Die dritte Anweisung definiert die Variable OUTFILE, diesmal unter Zuhilfenahme des Kommandos date. Die Syntax $(...) entspricht dem Verwenden von Backticks (siehe auch Kasten “Backticks oder nicht?”). Die Art von Operation ist unter dem Namen Kommandosubstitution bekannt.
In der letzten Zeile steht dann der eigentliche Tar-Befehl, der nun die Liste aus der Datei sowie eventuelle zusätzliche Argumente berücksichtigt, die Sie archivieren wollen. Verwenden Sie eine Variable innerhalb einer anderen Anweisung, vergessen Sie nie das Dollar-Zeichen vor den Variablennamen zu setzen, wie zum Beispiel $DIRS.
Backticks oder nicht?
Bei der Kommando-Substitution hat bereits vor geraumer Zeit die Schreibweise $(...) die ältere Variante mit Backticks abgelöst. Dafür gibt es gute Gründe:
- Bessere Lesbarkeit: In vielen Darstellungsformen verwechselt man den Backtick ` sehr leicht mit dem einfachen Anführungszeichen ‘.
- Besser einzutippen: Auf vielen internationalen Keyboard-Layouts lässt sich der Backtick nur schwer erreichen, auf manchen fehlt er ganz (etwa bei italienischen Standard-Keyboards).
- Eindeutigere Syntax: Insbesondere beim Verschachteln von Substitutionen sowie beim Quoting entsteht ein übersichtlicheres Konstrukt.
Daher sollten Sie in Ihren Skripten der Variante $(...) gegenüber der in der Bash zwar noch funktionierenden, aber als obsolet geltenden Backtick-Methode den Vorzug einräumen. Es gibt eigentlich nur zwei Gründe, den Backtick noch zu nutzen: die Macht der Gewohnheit (viele routinierte Skript-Autoren sind mit dem “Fliegenschiss” aufgewachsen) und den Zwang zur Kompatibilität mit älteren Shells (Bourne- und Korn-Shell) insbesondere auf anderen Unix-Systemen.
Tests
Das Skript in Listing 2 prüft die Exaktheit der Argumente weniger gründlich als die vorherigen Beispiele. Etwas anspruchsvoller gestaltet sich Listing 3, das diese Prüfung wieder einführt und noch mehr Flexibilität gewährleistet. Für das schnelle Bearbeiten von Argumenten kommt hier die Getopts-Funktion der Bash zum Einsatz.
Listing 3
#!/bin/bash
# Ablageort und Namensanfang (Prefix) vorgeben
DEST="/save"
PREFIX="backup"
while getopts ":f:bn:d:" OPT; do # Überprüfen der Parameter
case $OPT in
f) DIRS=$OPTARG ;; # -f <Datei mit Verzeichnisliste>
b) ZIP="j"; EXT="tbz" ;; # -b = bzip2 statt gzip verwenden
n) PREFIX=$OPTARG ;; # -n <Prefix>
d) if [ "${OPTARG:0:1}" = "/" ]; then # -d <Archivverzeichnis>
DEST=$OPTARG
else
echo "Zielverzeichnis muss mit / beginnen."
exit 1 # Skript mit Fehler-Status beenden
fi ;;
:) echo "Sie müssen ein Argument für die Option -$OPTARG angeben."
exit 1 ;;
*) echo "Kein gültiges Argument: -$OPTARG"
exit 1 ;;
esac
done
[... Listing 4 ...]
Die ersten beiden Befehle weisen den Variablen DEST und PREFIX die gewünschten Werte zu: das Verzeichnis, in dem die Archivdatei landet, sowie den Anfang des Dateinamens für das Archiv. Das Präfix erhält anschließend als Zusatz die Zeichenkette des aktuellen Datums (wie in Listing 2 oder Listing 4 definiert). Der Rest dieses Abschnitts im Skript folgt der Struktur einer While-Schleife:
while Bedingung;Befehle done
Das Skript durchläuft die Schleife, solange die Bedingung erfüllt ist, und endet, wenn der Test negativ ausfällt – in diesem Fall das Konstrukt getopts "f:bn:d: " OPT. Die Ausdrücke für die Bedingung stehen häufig in eckigen Klammern, wie bei der If-Anweisung im vorangegangenen Beispiel zu sehen, aber die eigentlichen Befehle nicht. Technisch gesehen rufen eckige Klammern den Test-Befehl auf.
Der Befehl Getopts geht jede Option der Reihe nach durch, zusammen mit den eventuellen Argumenten dazu. Die Optionsbuchstaben landen nacheinander im zweiten Argument von Getopts (im vorliegenden Fall OPT), die Argumente in OPTARG. Das erste Argument von Getopts ist ein String der erlaubten Buchstaben (Groß- und Kleinschreibung unterscheidend).
In der Kommandozeile muss vor Optionsbuchstaben ein Bindestrich stehen. Einige Optionen verlangen ein Argument. Das zeigt immer der danach stehende Doppelpunkt – im Beispiel sind es die Buchstaben f, n und d. Der vor der ersten Option stehende Doppelpunkt verhindert, dass Getopts selbst Fehlermeldungen ausgibt – das wollen wir selbst übernehmen.
Innerhalb der While-Schleife sorgt eine Case-Anweisung für das fachgerechte Bearbeiten der Optionen. Die Anweisung vergleicht den Wert von OPT mit einer Liste von Mustern. Bei jedem Muster handelt es sich um eine Zeichenkette, die Platzhalter enthalten darf. Ein runde schließende Klammer beendet das Muster. Die Reihenfolge ist wichtig: Das erste passende Muster gewinnt.
Im Beispiel sind neben den Mustern für die erlaubten Optionsbuchstaben zusätzlich ein Doppelpunkt und ein Sternchen als Jokerzeichen für alles definiert, was die anderen Muster nicht abfangen. Die auszuführenden Befehle bei den einzelnen Optionen unterscheiden sich, jeder Abschnitt endet mit doppeltem Semikolon.

