In der Shell stehen viele Mechanismen zur Verf<72>gung, die auch aus anderen Sprachen bekannt sind. Um den Umfang dieses Dokuments nicht zu sprengen, werden an dieser Stelle nur die wichtigsten vorgestellt.
\section{Grunds<EFBFBD>tzliches}
Zun<EFBFBD>chst soll die Frage gekl<6B>rt werden, wie man <20>berhaupt ein ausf<73>hrbares Shell-Skript schreibt. Dabei wird vorausgesetzt, da<64> dem Benutzer der Umgang mit mindestens einem Texteditor\index{Texteditor} (\texttt{vi}\index{vi=\texttt{vi}}, \texttt{emacs}\index{emacs=\texttt{emacs}} etc.) bekannt ist.
Zun<EFBFBD>chst mu<6D> mit Hilfe des Editors eine Textdatei angelegt werden, in die der `Quelltext' geschrieben wird. Wie der aussieht, sollte man anhand der folgenden Abschnitte und der Beispiele im Anhang erkennen k<>nnen. Beim Schreiben sollte man nicht mit den Kommentaren\index{Kommentar} geizen, da ein Shell-Skript auch schon mal sehr unleserlich werden kann.
Nach dem Abspeichern der Datei unter einem geeigneten Namen\footnote{Bitte
\emph{nicht} den Namen \texttt{test}\index{test=\texttt{test}} verwenden. Es
existiert ein Unix-Systemkommando mit diesem Namen. Dieses steht fast immer
eher im Pfad, d. h. beim Kommando \texttt{test} w<>rde nicht das eigene Skript
ausgef<EFBFBD>hrt, sondern das Systemkommando. Dies ist einer der h<>ufigsten und
zugleich einer der verwirrendsten Anf<6E>ngerfehler. Mehr zu dem
\texttt{test}-Kommando unter \ref{bedingungen}.} mu<6D> die sie ausf<73>hrbar gemacht
werden. Das geht mit dem Unix-Kommando
\texttt{chmod}\index{chmod=\texttt{chmod}}. Rechte k<>nnen unter Unix getrennt
f<EFBFBD>r den Benutzer (user, \texttt{u}), die Gruppe (group, \texttt{g}) oder andere
(others, \texttt{o}) vergeben werden. Au<41>erdem kann man die Rechte f<>r alle
Gruppen zusammen (all, a) setzen. Man kann getrennt die Rechte f<>r das lesen
(read, \texttt{r}), das schreiben (write, \texttt{w}) und die Ausf<73>hrung
(execution, \texttt{x}) vergeben. Damit die Datei f<>r einen Benutzer wirklich
ausf<EFBFBD>hrbar ist, mu<6D> er das Lese- und das
Ausf<EFBFBD>hrungsrecht\index{Aus<EFBFBD>hrungsrecht} haben. Um die Rechte zu setzen, mu<6D> man
\texttt{chmod} in Parametern mitgeben, worauf sich das Kommando bezieht, ob das
Recht gesetzt (\texttt{+}) oder weggenommen (\texttt{-}) werden soll, und
welche Rechte gemeint sind. Damit alle Benutzer das Skript ausf<73>hren d<>rfen,
benutzt man das Kommando \texttt{chmod ugo+rx name} oder einfach \texttt{chmod
+rx name}. Mit \texttt{chmod u+x name} hat nur der Besitzer der Datei
Dann kann das Skript gestartet werden. Da sich aus Sicherheitsgr<67>nden auf den meisten Systemen das aktuelle Verzeichnis nicht im Pfad des Benutzers befindet, mu<6D> man der Shell noch mitteilen, wo sie zu suchen hat: Mit \texttt{./name} wird versucht, im aktuellen Verzeichnis (\texttt{./}) ein Programm namens \texttt{name} auszuf<75>hren.
Die folgenden Mechanismen stehen in der Standard-Shell bereit, um mit Variablen zu hantieren. Bei allen Angaben ist der Doppelpunkt optional. Wenn er aber angegeben wird, mu<6D> die \textsl{Variable} einen Wert enthalten. \nopagebreak
Bei der Angabe von Dateinamen k<>nnen eine Reihe von Meta-Zeichen\footnote{Meta-Zeichen werden auch Wildcards, Joker-Zeichen oder Platzhalter genannt.} verwendet werden, um mehrere Dateien gleichzeitig anzusprechen oder um nicht den vollen Dateinamen ausschreiben zu m<>ssen.
Ausdruck}}\index{Ausdruck|see{Regul<EFBFBD>rer Ausdruck}} genannt. Sie bieten
wesentlich mehr M<>glichkeiten als die relativ einfachen Wildcards f<>r
Dateinamen.
In der folgenden Tabelle wird gezeigt, in welchen Unix-Tools welche Zeichen zur Verf<72>gung stehen. Eine ausf<73>hrlichere Beschreibung der Eintr<74>ge findet sich auf Seite \pageref{beschreibung_der_muster}. \nopagebreak
Bei einigen Tools (\texttt{ex}, \texttt{sed} und \texttt{ed}) werden zwei Muster angegeben: Ein Suchmuster (links) und ein Ersatzmuster (rechts). Nur die folgenden Zeichen sind in einem Ersatzmuster g<>ltig:\nopagebreak
\medskip\emph{Beispiele:} egrep- oder awk-Muster\nopagebreak
\LTXtable{\textwidth}{tab_beisp_muster_egrep.tex}
\medskip\emph{Beispiele:} ex- oder vi-Muster\nopagebreak
\LTXtable{\textwidth}{tab_beisp_muster_ex.tex}
\medskip\emph{Beispiele:} sed- oder grep-Muster\nopagebreak
\LTXtable{\textwidth}{tab_beisp_muster_sed.tex}
\medskip\emph{Beispiele:} Suchen und Ersetzen mit \texttt{sed} und \texttt{ex}. Im Folgenden werden Leerzeichen durch \Ovalbox{SPACE} und Tabulatoren durch \Ovalbox{TAB} gekennzeichnet. Befehle f<>r ex werden mit einem Doppelpunkt eingeleitet.\nopagebreak
Bei der Shell-Programmierung verf<72>gt man <20>ber <20>hnliche Konstrukte wie bei anderen Programmiersprachen, um den Ablauf des Programms zu steuern. Dazu geh<65>ren Funktionsaufrufe, Schleifen, Fallunterscheidungen und dergleichen.\nopagebreak
Dieser Befehl tut nichts, au<61>er den Status 0 zur<75>ckzugeben. Er wird benutzt, um Endlosschleifen\index{Endlosschleife} zu schreiben (siehe unter \ref{while}), oder um leere Bl<42>cke in \texttt{if}- oder \texttt{case}-Konstrukten\index{if=\texttt{if}}\index{case=\texttt{case}} m<>glich zu machen.
\medskip\emph{Beispiel:} Pr<50>fen, ob jemand angemeldet ist:\nopagebreak
Ein Shell-Skript kann in keiner Weise Einflu<6C> auf die umgebende Shell nehmen. Das hei<65>t, da<64> es beispielsweise nicht m<>glich ist, in einem Skript Variablen zu setzen, die dann in der aufrufenden Shell zur Verf<72>gung stehen. Genauso wenig ist es m<>glich, da<64> ein Skript den Pfad <20>ndert, in dem man sich befindet. Der Grund f<>r dieses Verhalten ist die Systemsicherheit. Man will verhindern, da<64> ein Skript unbemerkt <20>nderungen an der Benutzerumgebung vornimmt.
Wenn es aber doch gew<65>nscht wird, da<64> ein Skript die Umgebung des Benutzers <20>ndern kann, dann mu<6D> es mit dem Source-Kommando aufgerufen werden. Das wird in der Form \verb\source skriptname\ bzw. \verb\. skriptname\ angegeben. Er bewirkt <20>hnliches wie ein \verb\#include\ in der Programmiersprache C.
Die `gesourcte' Datei wird eingelesen und ausgef<65>hrt, als ob ihr Inhalt an der Stelle des Befehls stehen w<>rde. Diese Methode wird zum Beispiel beim Login in den Konfigurationsdateien des Benutzers (z. B. \verb\.profile\,\verb\.bashrc\) oder w<>hrend des Bootvorgangs in den Init-Skripten benutzt, um immer wieder ben<65>tigte Funktionen (Starten eines Dienstes, Statusmeldungen auf dem Bildschirm etc.) in einer zentralen Datei pflegen zu k<>nnen (siehe Beispiel unter~\ref{init-skript}).
Es ist in der Shell auch m<>glich, <20>hnlich wie in einer `richtigen' Programmiersprache Funktionen zu deklarieren und zu benutzen. Da die Bourne-Shell (\verb\sh\) nicht <20>ber Aliase\index{Aliase} verf<72>gt, k<>nnen einfache Funktionen als Ersatz dienen.
Die \texttt{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<62>ngig.
Die Syntax der \texttt{if}-Anweisung lautet wie folgt:\nopagebreak
\LTXtable{\textwidth}{tab_if.tex}
Wenn die \textsl{Bedingung1} erf<72>llt ist, werden die \textsl{Befehle1} ausgef<65>hrt; andernfalls, wenn die \textsl{Bedingung2} erf<72>llt ist, werden die \textsl{Befehle2} ausgef<65>hrt. Trifft keine Bedingung zu, sollen die \textsl{Befehle3} ausgef<65>hrt werden.
Bedingungen werden normalerweise mit dem Befehl \texttt{test}\index{test=\texttt{test}} (siehe unter \ref{bedingungen}) formuliert. Es kann aber auch der R<>ckgabewert\footnote{Siehe unter \ref{exitcode}.}\index{R<EFBFBD>ckgabewert} jedes anderen Kommandos ausgewertet werden. F<>r Bedingungen, die auf jeden Fall zutreffen sollen steht der Null-Befehl (\texttt{:}, siehe unter \ref{null-befehl}) zur Verf<72>gung.
\medskip\emph{Beispiele:} Man achte auf die Positionierung der Semikola\footnote{Und man verzeihe mir einen eventuell falschen Plural\ldots :-)}.\nopagebreak
Auch die \texttt{case}-Anweisung ist vergleichbar in vielen anderen Sprachen vorhanden. Sie dient, <20>hnlich wie die \texttt{if}-Anweisung zur Fallunterscheidung\index{Fallunterscheidung|see{case}}\index{Fallunterscheidung|see{if}}. Allerdings wird hier nicht nur zwischen zwei F<>llen unterschieden (Entweder / Oder), sondern es sind mehrere F<>lle m<>glich. Man kann die \texttt{case}-Anweisung auch durch eine geschachtelte \texttt{if}-Anweisung v<>llig umgehen, allerdings ist sie ein elegantes Mittel um den Code lesbar zu halten.
Die Syntax der \texttt{case}-Anweisung lautet wie folgt:\nopagebreak
\LTXtable{\textwidth}{tab_case.tex}
Wenn der \textsl{Wert} mit dem \textsl{Muster1}<20>bereinstimmt, wird die entsprechende Befehlsfolge\index{Befehls>-folge} (\textsl{Befehle1}) ausgef<65>hrt, bei <20>bereinstimmung mit \textsl{Muster2} werden die Kommandos der zweiten Befehlsfolge\index{Befehls>-folge} (\textsl{Befehle2}) ausgef<65>hrt, usw. Der letzte Befehl in jeder Gruppe mu<6D> mit \texttt{;;} gekennzeichnet werden. Das bedeutet f<>r die Shell soviel wie `springe zum n<>chsten \texttt{esac}', so da<64> die anderen Bedingungen nicht mehr <20>berpr<70>ft werden.
In den Mustern sind die gleichen Meta-Zeichen\index{Meta-Zeichen} erlaubt wie bei der Auswahl von Dateinamen. Das bedeutet, da<64> man durch ein einfaches \texttt{*}\index{*=\texttt{*}} den Default-Pfad kennzeichnen kann. Dieser wird dann durchlaufen, wenn kein anderes Muster zutrifft. Wenn in einer Zeile mehrere Muster angegeben werden sollen, m<>ssen sie durch ein Pipezeichen (\texttt{|}, logisches ODER) getrennt werden.
Die \texttt{while}-Schleife ist wieder ein Konstrukt, das einem aus vielen anderen Sprachen bekannt ist: die Kopfgesteuerte Schleife.
Die Syntax der \texttt{while}-Schleife lautet wie folgt:\nopagebreak
\LTXtable{\textwidth}{tab_while.tex}
Die \textsl{Befehle} werden so lange ausgef<65>hrt, wie die \textsl{Bedingung} erf<72>llt ist. Dabei wird die \textsl{Bedingung} vor der Ausf<73>hrung der \textsl{Befehle}<20>berpr<70>ft. Die \textsl{Bedingung} wird dabei <20>blicherweise, genau wie bei der \texttt{if}-Anweisung, mit mit dem Befehl \texttt{test}\index{test=\texttt{test}} (siehe unter \ref{bedingungen}) formuliert. Wenn die Ausf<73>hrung eines Schleifendurchlaufs bzw der ganzen Schleife abgebrochen werden soll, m<>ssen die Kommandos \texttt{continue}\index{continue=\texttt{continue}} (\ref{continue}) bzw. \texttt{break}\index{break=\texttt{break}} (\ref{break}) benutzt werden.
\medskip\emph{Beispiel:}\nopagebreak
\LTXtable{\textwidth}{tab_beisp_while.tex}
Eine Standard-Anwendung der \texttt{while}-Schleife ist der Ersatz f<>r die
\medskip\emph{Beispiel:} Hier wird die Bedingung nicht per \texttt{test} sondern mit dem R<>ckgabewert\index{R<EFBFBD>ckgabewert} des Programms \texttt{grep}\index{grep=\texttt{grep}} formuliert.\nopagebreak
Die Syntax der \texttt{continue}-Anweisung lautet wie folgt:\nopagebreak
\LTXtable{\textwidth}{tab_continue.tex}
Man benutzt \texttt{continue} um die restlichen Befehle in einer Schleife zu <20>berspringen und mit dem n<>chsten Schleifendurchlauf anzufangen. Wenn der Parameter \textsl{n} angegeben wird, werden \textsl{n} Schleifenebenen <20>bersprungen.
Die Syntax der \texttt{exit}-Anweisung lautet wie folgt:\nopagebreak
\LTXtable{\textwidth}{tab_exit.tex}
Die \texttt{exit}-Anweisung wird benutzt, um ein Skript zu beenden. Wenn der Parameter \textsl{n} angegeben wird, wird er von dem Skript als Exit-Code zur<75>ckgegeben.
Eines der markantesten Konzepte, das in Shell-Skripten benutzt wird, ist das der Datenstr<74>me. Die meisten der vielen Unix-Tools bieten die M<>glichkeit, Eingaben aus der sogenannten Standard-Eingabe entgegenzunehmen und Ausgaben dementsprechend auf der Standard-Ausgabe zu machen. Es gibt noch einen dritten Kanal f<>r Fehlermeldungen, so da<64> man eine einfache M<>glichkeit hat, fehlerhafte Programmdurchl<68>ufe zu behandeln indem man die Fehlermeldungen von den restlichen Ausgaben trennt.
Es folgt eine Aufstellung der drei Standardkan<61>le:\nopagebreak
Gerade der Mechanismus mit dem Piping sollte nicht untersch<63>tzt werden. Er dient nicht nur dazu, relativ kleine Texte zwischen Tools hin- und herzureichen. An dem folgenden Beispiel soll die M<>chtigkeit dieses kleinen Zeichens gezeigt werden:\nopagebreak
Es ist mit den passenden Tools unter Unix m<>glich, eine ganze Audio-CD mit zwei Befehlen an der Kommandozeile zu duplizieren. Das erste Kommando veranla<6C>t, da<64> die TOC (Table Of Contents) der CD in die Datei cd.toc geschrieben wird. Das dauert nur wenige Sekunden. Die Pipe steckt im zweiten Befehl. Hier wird der eigentliche Inhalt der CD mit dem Tool `cdparanoia' ausgelesen. Da kein Dateiname angegeben wird, schreibt cdparanoia die Daten auf seine Standard-Ausgabe. Diese wird von dem Brennprogramm `cdrdao' <20>bernommen und in Verbindung mit der TOC `on the fly' auf die CD geschrieben.\label{cdrdao}\nopagebreak