Login
Newsletter
Werbung

So, 16. Oktober 2005, 00:00

Ein Shellskript-Template

Um das Rad nicht jedes Mal neu erfinden zu müssen, liefert eine Shellskript-Schablone alle wichtigen Features, die man von einem Kommando unter UNIX erwarten darf. Man füge nur noch ein wenig Funktionalität hinzu!

Wofür eine Shellskript-Schablone?

Das Schöne an Shellskripten ist, dass sie so schnell geschrieben sind. Man tippt ein etwas längeres Kommando am Shellprompt ein, erkennt dessen Nützlichkeit (oder möchte sich nur spätere Tipparbeit sparen) und speichert das Kommando in einer Datei.

Die Probleme mit diesem Ansatz beginnen etwas später:

  • Meist enthalten solche Skripte festkodierte Datei- oder Pfadnamen.
  • Sie geben keine aussagekräftigen Fehlermeldungen oder gar Exitcodes zurück.
  • Auch andere UNIX-Konventionen werden nicht beachtet: Fehlermeldungen auf die Standardfehlerausgabe (stderr) schreiben, Optionen parsen, mehrere Argumente bei einem Aufruf bearbeiten können usw.
  • Mangels Kommentaren oder Usage-Meldung vergisst man meist selbst den Sinn und Zweck des Skripts.

Hat man nun ein Shellskript-Template, welches bereits auf solche Wünsche vorbereitet ist, braucht man nur das Kommando in dieses Template hineinzukopieren, eventuell Überflüssiges herauszulöschen und wenige Anpassungen vorzunehmen.

Das Shellskript-Template

Für die Ungeduldigen also jetzt das Template. Geduldigere können danach noch weiterlesen, was dieses Skript macht und wie es das schafft.

#!/bin/bash
# Skript: skript.sh
# Zweck: Basis für eigene Skripte, enthaelt bereits
# einige Skript-Standardelemente (usage-Funktion,
# Optionen parsen mittels getopts, vordefinierte
# Variablen...)
# Globale Variablen
SCRIPTNAME=$(basename $0 .sh)
EXIT_SUCCESS=0
EXIT_FAILURE=1
EXIT_ERROR=2
EXIT_BUG=10
# Variablen für Optionsschalter hier mit Default-Werten vorbelegen
VERBOSE=n
OPTFILE=""
# Funktionen
function usage {
 echo "Usage: $SCRIPTNAME [-h] [-v] [-o arg] file ..." >&2
 [[ $# -eq 1 ]] && exit $1 || exit $EXIT_FAILURE
}
# Die Option -h für Hilfe sollte immer vorhanden sein, die Optionen
# -v und -o sind als Beispiele gedacht. -o hat ein Optionsargument;
# man beachte das auf "o" folgende ":".
while getopts ':o:vh' OPTION ; do
 case $OPTION in
 v) VERBOSE=y
 ;;
 o) OPTFILE="$OPTARG"
 ;;
 h) usage $EXIT_SUCCESS
 ;;
 \?) echo "Unbekannte Option \"-$OPTARG\"." >&2
 usage $EXIT_ERROR
 ;;
 :) echo "Option \"-$OPTARG\" benötigt ein Argument." >&2
 usage $EXIT_ERROR
 ;;
 *) echo "Dies kann eigentlich gar nicht passiert sein..."
>&2
 usage $EXIT_BUG
 ;;
 esac
done
# Verbrauchte Argumente überspringen
shift $(( OPTIND - 1 ))
# Eventuelle Tests auf min./max. Anzahl Argumente hier
if (( $# < 1 )) ; then
 echo "Mindestens ein Argument beim Aufruf übergeben." >&2
 usage $EXIT_ERROR
fi
# Schleife über alle Argumente
for ARG ; do
 if [[ $VERBOSE = y ]] ; then
 echo -n "Argument: "
 fi
 echo $ARG
done
exit $EXIT_SUCCESS

Erläuterungen zur Schablone

Bash als Interpreter

Dieses Skript verwendet einige Features, die die alte Bourne-Shell (sh) nicht kennt: (( )), $(( )), [[ ]] u.a. Also fordert unser Skript vom System die Bash als Interpreter: #!/bin/bash

Diese Zeile muss die allererste des Skripts sein. Der Loader des UNIX-Systems erkennt an den ersten zwei Bytes der Datei (#!), dass es sich um ein zu interpretierendes Skript handelt. Der Name des Interpreters folgt direkt auf die #!-Zeichenkombination, die man in englischen Texten auch häufig als Shebang bezeichnet.

Wer auf UNIX-Systemen ohne bash arbeitet, verfügt meist über die Korn-Shell; da diese ebenfalls über die hier verwendeten Konstrukte verfügt, kann man die erste Zeile auch die ksh anfordern: #!/bin/ksh. Eine weitergehende Anpassung des Templates ist nicht notwendig.

Globale Variablen

Es lohnt sich immer, globale Variable am Anfang eines Skriptes zusammenzufassen und dort am besten auch mit sinnvollen Defaultwerten zu belegen. Der Name des Skripts ($SCRIPTNAME) kann in Fehlermeldungen oder Statusmeldungen weiterverwendet werden. Aussagekräftige Namen für Exitcodes, die im Erfolgs-, Misserfolgs-, Fehler- oder Skriptfehlerfall an den aufrufenden Prozess zurückgegeben werden, machen den Abbruchcharakter im späteren Skript deutlich.

Fehlermeldungen nach stderr

echo gibt alle übergebenen Kommandos nach stdout (Standardausgabe) aus. Wenn man das eigene Skript eine Fehlermeldung machen lassen muss, sollte diese Ausgabe nach stderr (Standardfehlerausgabe) umgelenkt werden: echo "Fehler" >&2. Diese Umlenkung liest sich als "Lenke die Standardausgabe (>) auf die Standardfehlerausgabe (&2) um."

Usage-Funktion

Im Fehlerfall ist es gute Sitte, den korrekten Aufruf des Skripts zu beschreiben. Die Funktion usage macht genau das. Außerdem markiert diese Funktion die Stelle, an der man eigene Funktionen aufführen kann, wenn das Skript etwas größer werden sollte.

getopts zum Parsen von Optionen

Um die Arbeitsweise eines Kommandos zu variieren, verwendet man unter UNIX Optionen. Dies sind Argumente, die mit einem "-" beginnen und entweder als Schalter (gesetzt/nicht gesetzt) funktionieren oder ein Optionsargument mitgegeben bekommen. Solange ein Shellskript nur eine einzige Option erkennen muss, ist das Parsen noch leicht. Wenn es aber mehrere werden, dann dürfen diese Optionen nach UNIX-Konventionen beliebig zusammen gruppiert werden: ls -l -a, ls -la und ls -al sind gleichwertig! Damit diese Funktionalität nicht immer wieder (meist fehlerhaft oder nur eingeschränkt ) neu implementiert werden muss, gibt es die getopts-Funktion.

Das erste Argument zu getopts ist eine Zeichenkette, welche die erlaubten Optionen definiert. In unserem Beispiel sind das die Optionen o, h und v. Da auf den Buchstaben o ein Doppelpunkt folgt, wird für -o ein Optionsargument erwartet. Der erste Doppelpunkt weist getopts an, keine eigenen Fehlermeldungen auszugeben, damit wir ungestört unsere eigenen Meldungen ausgeben können.

Das zweite Argument zu getopts ist der Name der Variablen, die mit der erkannten Option gefüllt werden soll. Ein eventuelles Optionsargument findet man in der Variablen OPTARG.

Fehlerfälle wie unbekannte Optionen und fehlende Optionsargumente sind bereits abgehandelt. Zum Ende der Schleife, also wenn getopts keine weiteren Optionen mehr oder ein "--" erkennt, werden die abgearbeiteten Optionen mittels shift aus der Argumentliste des Skripts entfernt.

Check auf minimale/maximale Anzahl Argumente

Häufig macht der Aufruf des Skriptes nur mit mindestens einem Argument (Dateiname, Username, ...) Sinn. Eine entsprechende Prüfung ist bereits vorgeben. Sie lässt sich schnell erweitern oder aber auch entfernen.

Pro-Linux
Pro-Linux @Facebook
Neue Nachrichten
Werbung