Viele ueberarbeitungen

This commit is contained in:
rschaten
2004-11-12 12:07:32 +00:00
parent 7eea8ed0e9
commit 14dec49967
13 changed files with 568 additions and 52 deletions

View File

@ -1,6 +1,12 @@
% $Id$
\chapter{Wie sieht ein Shell-Skript aus?}
Wie schon erw<72>hnt, kann ein Shell-Skript beinahe alles, was eine `richtige' Programmiersprache auch kann. Bei der Entwicklung sollte man nur bedenken, da<64> gerade die Ausf<73>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<72>gung ziehen.
Wie schon erw<72>hnt, kann ein Shell-Skript beinahe alles, was eine `richtige'
Programmiersprache auch kann. Bei der Entwicklung sollte man nur bedenken, da<64>
gerade die Ausf<73>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<72>gung ziehen.
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.
@ -51,7 +57,12 @@ Auf den meisten Systemen befindet sich im Pfad der Eintrag \texttt{\~{}/bin} bzw
\subsection{R<EFBFBD>ckgabewerte}\label{exitcode}\index{R<EFBFBD>ckgabewert|(textbf}\index{Exit-Code|see{R<EFBFBD>ckgabewert}}\index{Exit-Status|see{R<EFBFBD>ckgabewert}}
Wenn unter Unix ein Proze<7A> beendet wird, gibt er einen R<>ckgabewert (auch Exit-Code oder Exit-Status genannt) an seinen aufrufenden Proze<7A> zur<75>ck. So kann der Mutterproze<7A> kontrollieren, ob die Ausf<73>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<7A> beendet wird, gibt er einen R<>ckgabewert (auch
Exit-Code oder Exit-Status genannt) an seinen aufrufenden Proze<7A> zur<75>ck. So
kann der Mutterproze<7A> kontrollieren, ob die Ausf<73>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 <20>ber Befehlsformen (\ref{befehlsformen}).
In der Bourne-Shell wird der Exit-Code des letzten aufgerufenen Programms in der Variable \texttt{\$?}\index{\$?=\texttt{\$?}} abgelegt. <20>blicherweise geben Programme den Wert 0 zur<75>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<65>scht wird:
\LTXtable{\textwidth}{tab_beisp_exitcode_lpr.tex}
N<EFBFBD>heres zur Verkn<6B>pfung von Aufrufen steht im Kapitel <20>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. <20>blicherweise geben
Programme den Wert 0 zur<75>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<65>scht wird:
\LTXtable{\textwidth}{tab_beisp_exitcode_lpr.tex}
N<EFBFBD>heres zur Verkn<6B>pfung von Aufrufen steht im Kapitel <20>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<EFBFBD>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<75>ckgeben. Wie das geht, steht in dem Abschnitt zu \texttt{exit} (\ref{exit}).
\index{R<EFBFBD>ckgabewert|)}
\section{Variablen}\index{Variablen|(textbf}
In einem Shell-Skript hat man --- genau wie bei der interaktiven Nutzung der Shell --- M<>glichkeiten, <20>ber Variablen zu verf<72>gen. Anders als in den meisten modernen Programmiersprachen gibt es aber keine Datentypen\index{Datentypen} wie Ganzzahlen, Flie<69>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 <20>bernehmen soll, dann mu<6D> das verarbeitende Programm die Variable entsprechend interpretieren\footnote{F<EFBFBD>r arithmetische Operationen steht das Programm \texttt{expr}\index{expr=\texttt{expr}} zur Verf<72>gung (siehe Z<>hlschleifen-Beispiel unter \ref{while})}.
In einem Shell-Skript hat man~--~genau wie bei der interaktiven Nutzung der
Shell~--~M<>glichkeiten, <20>ber Variablen zu verf<72>gen. Anders als in den meisten
modernen Programmiersprachen gibt es aber keine Datentypen\index{Datentypen}
wie Ganzzahlen, Flie<69>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
<EFBFBD>bernehmen soll, dann mu<6D> das verarbeitende Programm die Variable entsprechend
interpretieren\footnote{F<EFBFBD>r arithmetische Operationen steht das Programm
\texttt{expr}\index{expr=\texttt{expr}} zur Verf<72>gung (siehe
Z<EFBFBD>hlschleifen-Beispiel unter \ref{while})}.
Man mu<6D> 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<64>tzlich werden Variablen w<>hrend der Ausf<73>hrung des Skriptes immer an den Stellen ersetzt, an denen sie stehen. Das passiert in jeder Zeile, unmittelbar bevor sie ausgef<65>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<6D> 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<64>tzlich
werden Variablen w<>hrend der Ausf<73>hrung des Skriptes immer an den Stellen
ersetzt, an denen sie stehen. Das passiert in jeder Zeile, unmittelbar bevor
sie ausgef<65>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<75>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<75>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<6E>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<6E>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<64>cke auswerten kann\footnote{\texttt{if} und Konsorten pr<70>fen nur den R<>ckgabewert\index{R<EFBFBD>ckgabewert} eines aufgerufenen Programmes --- 0 bedeutet `true', alles andere bedeutet `false', siehe auch \ref{exitcode}.}, mu<6D> dazu ein externes Programm benutzt werden. Dieses Programm hei<65>t \verb\test\\index{test=\texttt{test}}. <20>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<69>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. <20>. lesbarer zu machen.
Da die Standard-Shell keine arithmetischen oder logischen Ausdr<64>cke auswerten
kann\footnote{\texttt{if} und Konsorten pr<70>fen nur den
R<EFBFBD>ckgabewert\index{R<EFBFBD>ckgabewert} eines aufgerufenen Programmes~--~0 bedeutet
`true', alles andere bedeutet `false', siehe auch \ref{exitcode}.}, mu<6D> dazu
ein externes Programm benutzt werden. Dieses Programm hei<65>t
\verb\test\\index{test=\texttt{test}}. <20>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<EFBFBD>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. <20>. lesbarer zu machen.
Das \verb\test\-Programm bietet sehr umfangreiche Optionen an. Dazu geh<65>ren Dateitests und Vergleiche von Zeichenfolgen oder ganzen Zahlen. Diese Bedingungen k<>nnen auch durch Verkn<6B>pfungen kombiniert werden.
Das \verb\test\-Programm bietet sehr umfangreiche Optionen an. Dazu geh<65>ren
Dateitests und Vergleiche von Zeichenfolgen oder ganzen Zahlen. Diese
Bedingungen k<>nnen auch durch Verkn<6B>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 <20>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 <20>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<6D> man dazu die \texttt{while}-Schleife\index{while=\texttt{while}} `mi<6D>brauchen' (siehe unter \ref{while}).}.
Dieses Konstrukt <20>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 <20>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<6D> man dazu die
\texttt{while}-Schleife\index{while=\texttt{while}} `mi<6D>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<65>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<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.
Die \textsl{Befehle} werden ausgef<65>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<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{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 <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<EFBFBD>hrung eines Schleifendurchlaufs bzw der ganzen
formuliert. Wenn die Aus\-f<EFBFBD>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.