Viele ueberarbeitungen
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
% $Id$
|
||||
\chapter{Wie sieht ein Shell-Skript aus?}
|
||||
Wie schon erwähnt, kann ein Shell-Skript beinahe alles, was eine `richtige' Programmiersprache auch kann. Bei der Entwicklung sollte man nur bedenken, daß gerade die Ausführung von externen Kommandos --- und das ist eine der Standard-Techniken bei der Shell-Programmierung --- nur sehr langsam vonstatten geht. Für Anwendungen bei denen z. B. viele Rechnungen oder Stringbearbeitungen gemacht werden müssen, sollte man also ggf. die Benutzung einer anderen Sprache, beispielsweise Perl\index{Perl}, in Erwägung ziehen.
|
||||
Wie schon erwähnt, kann ein Shell-Skript beinahe alles, was eine `richtige'
|
||||
Programmiersprache auch kann. Bei der Entwicklung sollte man nur bedenken, daß
|
||||
gerade die Ausführung von externen Kommandos~--~und das ist eine der
|
||||
Standard-Techniken bei der Shell-Programmierung~--~nur sehr langsam vonstatten
|
||||
geht. Für Anwendungen bei denen z. B. viele Rechnungen oder Stringbearbeitungen
|
||||
gemacht werden müssen, sollte man also ggf. die Benutzung einer anderen
|
||||
Sprache, beispielsweise Perl\index{Perl}, in Erwägung ziehen.
|
||||
|
||||
In der Shell stehen viele Mechanismen zur Verfügung, die auch aus anderen Sprachen bekannt sind. Um den Umfang dieses Dokuments nicht zu sprengen, werden an dieser Stelle nur die wichtigsten vorgestellt.
|
||||
|
||||
@@ -51,7 +57,12 @@ Auf den meisten Systemen befindet sich im Pfad der Eintrag \texttt{\~{}/bin} bzw
|
||||
|
||||
\subsection{Rückgabewerte}\label{exitcode}\index{Rückgabewert|(textbf}\index{Exit-Code|see{Rückgabewert}}\index{Exit-Status|see{Rückgabewert}}
|
||||
|
||||
Wenn unter Unix ein Prozeß beendet wird, gibt er einen Rückgabewert (auch Exit-Code oder Exit-Status genannt) an seinen aufrufenden Prozeß zurück. So kann der Mutterprozeß kontrollieren, ob die Ausführung des Tochterprozesses ohne Fehler beendet wurde. In einigen Fällen (z. B. \texttt{grep}\index{grep=\texttt{grep}}) werden unterschiedliche Exit-Codes für unterschiedliche Ereignisse benutzt.
|
||||
Wenn unter Unix ein Prozeß beendet wird, gibt er einen Rückgabewert (auch
|
||||
Exit-Code oder Exit-Status genannt) an seinen aufrufenden Prozeß zurück. So
|
||||
kann der Mutterprozeß kontrollieren, ob die Ausführung des Tochterprozesses
|
||||
ohne Fehler beendet wurde. In einigen Fällen (z. B.
|
||||
\texttt{grep}\index{grep=\texttt{grep}}) werden unterschiedliche Exit-Codes für
|
||||
unterschiedliche Ereignisse benutzt.
|
||||
|
||||
Dieser Rückgabewert wird bei der interaktiven Benutzung der Shell nur selten
|
||||
benutzt, da Fehlermeldungen direkt vom Benutzer abgelesen werden können. Aber
|
||||
@@ -64,25 +75,67 @@ Beschreibung der Kommandos \texttt{if}\index{if=\texttt{if}} (\ref{if}),
|
||||
\texttt{until}\index{until=\texttt{until}} (\ref{until}), sowie in dem
|
||||
Abschnitt über Befehlsformen (\ref{befehlsformen}).
|
||||
|
||||
In der Bourne-Shell wird der Exit-Code des letzten aufgerufenen Programms in der Variable \texttt{\$?}\index{\$?=\texttt{\$?}} abgelegt. Üblicherweise geben Programme den Wert 0 zurück, bei irgendwelchen Problemen einen von 0 verschiedenen Wert. Das wird im folgenden Beispiel deutlich:
|
||||
\LTXtable{\textwidth}{tab_beisp_exitcode.tex}
|
||||
Normalerweise wird man den Exit-Code nicht in dieser Form abfragen. Sinnvoller ist folgendes Beispiel, in dem eine Datei erst gedruckt wird, und dann --- falls der Ausdruck erfolgreich war --- gelöscht wird:
|
||||
\LTXtable{\textwidth}{tab_beisp_exitcode_lpr.tex}
|
||||
Näheres zur Verknüpfung von Aufrufen steht im Kapitel über Befehlsformen (\ref{befehlsformen}). Beispiele zur Benutzung von Rückgabewerten in Schleifen finden sich im Anhang unter \ref{beisp_schleifen_exitcode}.
|
||||
In der Bourne-Shell wird der Exit-Code des letzten aufgerufenen Programms in
|
||||
der Variable \texttt{\$?}\index{\$?=\texttt{\$?}} abgelegt. Üblicherweise geben
|
||||
Programme den Wert 0 zurück, bei irgendwelchen Problemen einen von 0
|
||||
verschiedenen Wert. Das wird im folgenden Beispiel deutlich:
|
||||
|
||||
\LTXtable{\textwidth}{tab_beisp_exitcode.tex}
|
||||
|
||||
Normalerweise wird man den Exit-Code nicht in dieser Form abfragen. Sinnvoller
|
||||
ist folgendes Beispiel, in dem eine Datei erst gedruckt wird, und dann~--~falls
|
||||
der Ausdruck erfolgreich war ~--~elöscht wird:
|
||||
|
||||
\LTXtable{\textwidth}{tab_beisp_exitcode_lpr.tex}
|
||||
|
||||
Näheres zur Verknüpfung von Aufrufen steht im Kapitel über Befehlsformen
|
||||
(\ref{befehlsformen}). Beispiele zur Benutzung von Rückgabewerten in Schleifen
|
||||
finden sich im Anhang unter \ref{beisp_schleifen_exitcode}.
|
||||
|
||||
Auch Shell-Skripte können einen Rückgabewert an aufrufende Prozesse
|
||||
zurückgeben. Wie das geht, steht in dem Abschnitt zu \texttt{exit}
|
||||
(\ref{exit}).
|
||||
|
||||
Auch Shell-Skripte können einen Rückgabewert an aufrufende Prozesse zurückgeben. Wie das geht, steht in dem Abschnitt zu \texttt{exit} (\ref{exit}).
|
||||
\index{Rückgabewert|)}
|
||||
|
||||
|
||||
\section{Variablen}\index{Variablen|(textbf}
|
||||
|
||||
In einem Shell-Skript hat man --- genau wie bei der interaktiven Nutzung der Shell --- Möglichkeiten, über Variablen zu verfügen. Anders als in den meisten modernen Programmiersprachen gibt es aber keine Datentypen\index{Datentypen} wie Ganzzahlen, Fließkommazahlen oder Strings\footnote{Bei einigen modernen Shells (\texttt{csh}\index{C-Shell}, \texttt{tcsh}\index{TENEX-C-Shell}, \texttt{ksh}\index{Korn-Shell}, \texttt{bash}\index{Bourne-Again-Shell}, \texttt{zsh}\index{Z-Shell}...) hat man die Möglichkeit, Variablentypen zu vereinbaren. In der Bourne-Shell\index{Bourne-Shell} nicht.}. Alle Variablen werden als String gespeichert, wenn die Variable die Funktion einer Zahl übernehmen soll, dann muß das verarbeitende Programm die Variable entsprechend interpretieren\footnote{Für arithmetische Operationen steht das Programm \texttt{expr}\index{expr=\texttt{expr}} zur Verfügung (siehe Zählschleifen-Beispiel unter \ref{while})}.
|
||||
In einem Shell-Skript hat man~--~genau wie bei der interaktiven Nutzung der
|
||||
Shell~--~Möglichkeiten, über Variablen zu verfügen. Anders als in den meisten
|
||||
modernen Programmiersprachen gibt es aber keine Datentypen\index{Datentypen}
|
||||
wie Ganzzahlen, Fließkommazahlen oder Strings\footnote{Bei einigen modernen
|
||||
Shells (\texttt{csh}\index{C-Shell}, \texttt{tcsh}\index{TENEX-C-Shell},
|
||||
\texttt{ksh}\index{Korn-Shell}, \texttt{bash}\index{Bourne-Again-Shell},
|
||||
\texttt{zsh}\index{Z-Shell}...) hat man die Möglichkeit, Variablentypen zu
|
||||
vereinbaren. In der Bourne-Shell\index{Bourne-Shell} nicht.}. Alle Variablen
|
||||
werden als String gespeichert, wenn die Variable die Funktion einer Zahl
|
||||
übernehmen soll, dann muß das verarbeitende Programm die Variable entsprechend
|
||||
interpretieren\footnote{Für arithmetische Operationen steht das Programm
|
||||
\texttt{expr}\index{expr=\texttt{expr}} zur Verfügung (siehe
|
||||
Zählschleifen-Beispiel unter \ref{while})}.
|
||||
|
||||
Man muß bei der Benutzung von Variablen sehr aufpassen, wann die Variable expandiert\footnote{Mit \emph{Expansion}\index{Expansion} ist das Ersetzen des Variablennamens durch den Inhalt gemeint} wird und wann nicht. Grundsätzlich werden Variablen während der Ausführung des Skriptes immer an den Stellen ersetzt, an denen sie stehen. Das passiert in jeder Zeile, unmittelbar bevor sie ausgeführt wird. Es ist also auch möglich, in einer Variable einen Shell-Befehl abzulegen. Im Folgenden kann dann der Variablenname an der Stelle des Befehls stehen. Um die Expansion einer Variable zu verhindern, benutzt man das Quoting\index{Quoting} (siehe unter \ref{quoting}).
|
||||
Man muß bei der Benutzung von Variablen sehr aufpassen, wann die Variable
|
||||
expandiert\footnote{Mit \emph{Expansion}\index{Expansion} ist das Ersetzen des
|
||||
Variablennamens durch den Inhalt gemeint} wird und wann nicht. Grundsätzlich
|
||||
werden Variablen während der Ausführung des Skriptes immer an den Stellen
|
||||
ersetzt, an denen sie stehen. Das passiert in jeder Zeile, unmittelbar bevor
|
||||
sie ausgeführt wird. Es ist also auch möglich, in einer Variable einen
|
||||
Shell-Befehl abzulegen. Im Folgenden kann dann der Variablenname an der Stelle
|
||||
des Befehls stehen. Um die Expansion einer Variable zu verhindern, benutzt man
|
||||
das Quoting\index{Quoting} (siehe unter \ref{quoting}).
|
||||
|
||||
Wie aus diversen Beispielen hervorgeht, belegt man eine Variable, indem man dem Namen mit dem Gleichheitszeichen einen Wert zuweist. Dabei darf zwischen dem Namen und dem Gleichheitszeichen keine Leerstelle stehen, ansonsten erkennt die Shell den Variablennamen nicht als solchen und versucht, ein gleichnamiges Kommando auszuführen --- was meistens durch eine Fehlermeldung quittiert wird.
|
||||
Wie aus diversen Beispielen hervorgeht, belegt man eine Variable, indem man dem
|
||||
Namen mit dem Gleichheitszeichen einen Wert zuweist. Dabei darf zwischen dem
|
||||
Namen und dem Gleichheitszeichen keine Leerstelle stehen, ansonsten erkennt die
|
||||
Shell den Variablennamen nicht als solchen und versucht, ein gleichnamiges
|
||||
Kommando auszuführen~--~was meistens durch eine Fehlermeldung quittiert wird.
|
||||
|
||||
Wenn man auf den Inhalt einer Variablen zugreifen möchte, leitet man den
|
||||
Variablennamen durch ein \texttt{\$}-Zeichen ein. Alles was mit einem
|
||||
\texttt{\$} anfängt wird von der Shell als Variable angesehen und entsprechend
|
||||
behandelt (expandiert).
|
||||
|
||||
Wenn man auf den Inhalt einer Variablen zugreifen möchte, leitet man den Variablennamen durch ein \texttt{\$}-Zeichen ein. Alles was mit einem \texttt{\$} anfängt wird von der Shell als Variable angesehen und entsprechend behandelt (expandiert).
|
||||
\index{Variablen|)}
|
||||
|
||||
|
||||
@@ -271,7 +324,11 @@ Bei der Shell-Programmierung verf
|
||||
|
||||
\subsection{Kommentare\label{kommentare}\index{Kommentar|(textbf} (\texttt{\#})}\index{\#=\texttt{\#}|see{Kommentar}}
|
||||
|
||||
Kommentare in der Shell beginnen immer mit dem Nummern-Zeichen (\verb\#\). Dabei spielt es keine Rolle, ob das Zeichen am Anfang der Zeile steht, oder hinter irgendwelchen Befehlen. Alles von diesem Zeichen bis zum Zeilenende wird nicht beachtet (bis auf eine Ausnahme --- siehe unter \ref{auswahl_der_shell}).
|
||||
Kommentare in der Shell beginnen immer mit dem Nummern-Zeichen (\verb\#\).
|
||||
Dabei spielt es keine Rolle, ob das Zeichen am Anfang der Zeile steht, oder
|
||||
hinter irgendwelchen Befehlen. Alles von diesem Zeichen bis zum Zeilenende wird
|
||||
nicht beachtet (bis auf eine Ausnahme~--~siehe unter \ref{auswahl_der_shell}).
|
||||
|
||||
\index{Kommentar|)}
|
||||
|
||||
|
||||
@@ -330,9 +387,21 @@ durch die Eingabe von \verb\count\.\nopagebreak
|
||||
|
||||
\subsection{Bedingungen (\texttt{[ ]})}\label{bedingungen}\index{Bedingungen|see{test}}\index{[ ]=\texttt{[ ]}|see{test}}\index{test=\texttt{test}|(textbf}
|
||||
|
||||
Da die Standard-Shell keine arithmetischen oder logischen Ausdrücke auswerten kann\footnote{\texttt{if} und Konsorten prüfen nur den Rückgabewert\index{Rückgabewert} eines aufgerufenen Programmes --- 0 bedeutet `true', alles andere bedeutet `false', siehe auch \ref{exitcode}.}, muß dazu ein externes Programm benutzt werden. Dieses Programm heißt \verb\test\\index{test=\texttt{test}}. Üblicherweise besteht auf allen Systemen auch noch ein Link namens \verb\[\ auf dieses Programm. Dieser Link ist fast absolut gleichwertig zu benutzen (in dieser Form wird allerdings eine abschließende Klammer nach der Bedingung erwartet). Dementsprechend ist es auch zwingend erforderlich, nach der Klammer ein Leerzeichen zu schreiben. Das dient dazu, Bedingungen in \verb\if\-Abfragen u. ä. lesbarer zu machen.
|
||||
Da die Standard-Shell keine arithmetischen oder logischen Ausdrücke auswerten
|
||||
kann\footnote{\texttt{if} und Konsorten prüfen nur den
|
||||
Rückgabewert\index{Rückgabewert} eines aufgerufenen Programmes~--~0 bedeutet
|
||||
`true', alles andere bedeutet `false', siehe auch \ref{exitcode}.}, muß dazu
|
||||
ein externes Programm benutzt werden. Dieses Programm heißt
|
||||
\verb\test\\index{test=\texttt{test}}. Üblicherweise besteht auf allen Systemen
|
||||
auch noch ein Link namens \verb\[\ auf dieses Programm. Dieser Link ist fast
|
||||
absolut gleichwertig zu benutzen (in dieser Form wird allerdings eine
|
||||
abschließende Klammer nach der Bedingung erwartet). Dementsprechend ist es auch
|
||||
zwingend erforderlich, nach der Klammer ein Leerzeichen zu schreiben. Das dient
|
||||
dazu, Bedingungen in \verb\if\-Abfragen u. ä. lesbarer zu machen.
|
||||
|
||||
Das \verb\test\-Programm bietet sehr umfangreiche Optionen an. Dazu gehören Dateitests und Vergleiche von Zeichenfolgen oder ganzen Zahlen. Diese Bedingungen können auch durch Verknüpfungen kombiniert werden.
|
||||
Das \verb\test\-Programm bietet sehr umfangreiche Optionen an. Dazu gehören
|
||||
Dateitests und Vergleiche von Zeichenfolgen oder ganzen Zahlen. Diese
|
||||
Bedingungen können auch durch Verknüpfungen kombiniert werden.
|
||||
|
||||
\medskip\medskip\emph{Dateitests:}\index{Dateitests}\nopagebreak
|
||||
\LTXtable{\textwidth}{tab_bedingungen_dateitests.tex}
|
||||
@@ -387,12 +456,28 @@ In den Mustern sind die gleichen Meta-Zeichen\index{Meta-Zeichen} erlaubt wie be
|
||||
|
||||
\subsection{for\ldots}\label{for}\index{for=\texttt{for}|(textbf}\index{Schleife>for-=\texttt{for}-|see{for}}\index{in=\texttt{in}|see{for}}\index{in=\texttt{in}|see{case}}\index{do=\texttt{do}|see{for}}\index{do=\texttt{do}|see{while}}\index{do=\texttt{do}|see{until}}\index{do=\texttt{done}|see{for}}\index{do=\texttt{done}|see{while}}\index{do=\texttt{done}|see{until}}
|
||||
|
||||
Dieses Konstrukt ähnelt nur auf den ersten Blick seinen Pendants aus anderen Programmiersprachen. In anderen Sprachen wird die \texttt{for}-Schleife meistens dazu benutzt, eine Zählvariable über einen bestimmten Wertebereich iterieren zu lassen (\texttt{for i = 1 to 100\ldots next}). In der Shell dagegen wird die Laufvariable nicht mit aufeinanderfolgenden Zahlen belegt, sondern mit einzelnen Werten aus einer anzugebenden Liste\footnote{Wenn man trotzdem eine Laufvariable\index{Laufvariable} braucht, muß man dazu die \texttt{while}-Schleife\index{while=\texttt{while}} `mißbrauchen' (siehe unter \ref{while}).}.
|
||||
Dieses Konstrukt ähnelt nur auf den ersten Blick seinen Pendants aus anderen
|
||||
Programmiersprachen. In anderen Sprachen wird die \texttt{for}-Schleife
|
||||
meistens dazu benutzt, eine Zählvariable über einen bestimmten Wertebereich
|
||||
iterieren zu lassen (\texttt{for i = 1 to 100\ldots next}). In der Shell
|
||||
dagegen wird die Laufvariable nicht mit aufeinanderfolgenden Zahlen belegt,
|
||||
sondern mit einzelnen Werten aus einer anzugebenden Liste\footnote{Wenn man
|
||||
trotzdem eine Laufvariable\index{Laufvariable} braucht, muß man dazu die
|
||||
\texttt{while}-Schleife\index{while=\texttt{while}} `mißbrauchen' (siehe unter
|
||||
\ref{while}).}.
|
||||
|
||||
Die Syntax der \texttt{for}-Schleife lautet wie folgt:\nopagebreak
|
||||
\LTXtable{\textwidth}{tab_for.tex}
|
||||
|
||||
Die \textsl{Befehle} werden ausgeführt, wobei der Variablen \textsl{x} nacheinander die Werte aus der \textsl{Liste} zugewiesen werden. Wie man sieht ist die Angabe der \textsl{Liste} optional, wenn sie nicht angegeben wird, nimmt \textsl{x} der Reihe nach alle Werte aus \texttt{\$@} (in dieser vordefinierten Variablen liegen die Aufrufparameter --- siehe unter \ref{vordefinierte_variablen}) an. Wenn die Ausfü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.
|
||||
Die \textsl{Befehle} werden ausgeführt, wobei der Variablen \textsl{x}
|
||||
nacheinander die Werte aus der \textsl{Liste} zugewiesen werden. Wie man sieht
|
||||
ist die Angabe der \textsl{Liste} optional, wenn sie nicht angegeben wird,
|
||||
nimmt \textsl{x} der Reihe nach alle Werte aus \texttt{\$@} (in dieser
|
||||
vordefinierten Variablen liegen die Aufrufparameter~--~siehe unter
|
||||
\ref{vordefinierte_variablen}) an. Wenn die Ausfü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{Beispiele:}\nopagebreak
|
||||
\LTXtable{\textwidth}{tab_beisp_for.tex}
|
||||
@@ -441,7 +526,7 @@ Die Syntax der \texttt{until}-Schleife lautet wie folgt:\nopagebreak
|
||||
Die \textsl{Bedingung} wird dabei ü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ührung eines Schleifendurchlaufs bzw der ganzen
|
||||
formuliert. Wenn die Aus\-füh\-rung 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.
|
||||
|
||||
Reference in New Issue
Block a user