Viele Aenderungen

This commit is contained in:
rschaten
2004-12-02 13:54:06 +00:00
parent c0e556e25d
commit 15af99f29e
10 changed files with 873 additions and 57 deletions

View File

@@ -2,27 +2,31 @@
\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.
gerade die Aus\-füh\-rung von externen Kommandos~--~und das ist eine der
Standard-Techniken bei der Shell-Pro\-gram\-mie\-rung~--~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.
\section{Grundsätzliches}
\section{HowTo}
Zunächst soll die Frage geklärt werden, wie man überhaupt ein ausführbares Shell-Skript schreibt. Dabei wird vorausgesetzt, daß 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ächst soll die Frage geklärt werden, wie man überhaupt ein ausführbares
Shell-Skript schreibt. Dabei wird vorausgesetzt, daß 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.
Bei der Erstellung oder Bearbeitung von Shell-Skripten muß darauf geachtet
werden, daß sich keine CR/LF-Zeilenumbrüche einschleichen, wie dies leicht bei
der Benutzung von MS-DOS bzw. Windows-Systemen zur Bearbeitung von Skripten
über das Netzwerk passieren kann.
\subsection{HowTo}
Zunächst muß 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.
Zunächst muß mit Hilfe des Editors eine Textdatei angelegt werden, in die der
`Quelltext' geschrieben wird. Dabei muß darauf geachtet werden, daß sich keine
CR/LF-Zei\-len\-um\-brü\-che einschleichen, wie dies leicht bei der Benutzung
von MS-DOS bzw. Windows-Systemen zur Bearbeitung von Skripten über das Netzwerk
passieren kann. Wie der Quelltext 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
@@ -32,25 +36,16 @@ ausgef
zugleich einer der verwirrendsten Anfängerfehler. Mehr zu dem
\texttt{test}-Kommando unter \ref{bedingungen}.} muß die sie ausführbar gemacht
werden. Das geht mit dem Unix-Kommando
\texttt{chmod}\index{chmod=\texttt{chmod}}. Rechte können unter Unix getrennt
für den Benutzer (user, \texttt{u}), die Gruppe (group, \texttt{g}) oder andere
(others, \texttt{o}) vergeben werden. Auß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ührung
(execution, \texttt{x}) vergeben. Damit die Datei für einen Benutzer wirklich
ausführbar ist, muß er das Lese- und das
Ausführungsrecht\index{Ausührungsrecht} haben. Um die Rechte zu setzen, muß 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ü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
Ausführungsrechte.
\texttt{chmod}\index{chmod=\texttt{chmod}} und wird in Abschnitt \ref{chmod}
ausführlich beschrieben. An dieser Stelle reicht uns ein Aufruf in der Form
\texttt{chmod 755 dateiname}, um das Skript für alle Benutzer ausführbar zu
machen.
Um ein Shell-Skript ausführen zu können braucht es aus der Sicht des
ausführenden Benutzers mindestens die Rechte zum Lesen (r) und Ausführen (x).
Dann kann das Skript gestartet werden. Da sich aus Sicherheitsgründen auf den meisten Systemen das aktuelle Verzeichnis nicht im Pfad des Benutzers befindet, muß 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ühren.
Dann kann das Skript gestartet werden. Da sich aus Sicherheitsgründen auf den
meisten Systemen das aktuelle Verzeichnis nicht im Pfad des Benutzers befindet,
muß 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ühren.
Auf den meisten Systemen befindet sich im Pfad ein Verweis auf das Verzeichnis
\texttt{bin} unterhalb des Home-Verzeichnisses eines Benutzers. Das bedeutet
@@ -60,7 +55,7 @@ kann man an der Shell durch Eingabe von \texttt{echo
\$PATH}\index{\$PATH=\texttt{\$PATH}} herausfinden.
\subsection{Rückgabewerte}\label{exitcode}\index{Rückgabewert|(textbf}\index{Exit-Code|see{Rückgabewert}}\index{Exit-Status|see{Rückgabewert}}
\section{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
@@ -281,7 +276,9 @@ Ausdruck}}\index{Ausdruck|see{Regul
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ügung stehen. Eine ausführlichere Beschreibung der Einträge findet sich auf Seite \pageref{beschreibung_der_muster}. \nopagebreak
In der folgenden Tabelle wird gezeigt, in welchen Unix-Tools welche Zeichen zur
Ver\-\-gung stehen. Eine ausführlichere Beschreibung der Einträge findet sich
auf Seite \pageref{beschreibung_der_muster}. \nopagebreak
\LTXtable{\textwidth}{tab_mustererkennung_muster.tex}
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
@@ -358,6 +355,54 @@ F
\index{Arithmetik-Expansion|)}
\section{Eltern und Kinder: Prozeßordnung\label{prozessordnung}\index{Prozess|(textbf}\index{PID|see{Prozess}}\index{Parent-Prozess|see{Prozess}}\index{PPID|see{Prozess}}\index{Subshell|(textbf}}
Jedes laufende Programm auf einem Unixoiden System besteht aus einem oder
mehreren Prozessen, die jeweils eine eigene Prozeß-ID (PID) haben. Erzeugt ein
Programm mehrere Prozesse, sind die zu einer Prozeßgruppe zusammengefaßt. Jeder
laufende Prozeß\footnote{Es gibt eine Ausnahme: der Init-Prozeß, der immer die
PID 1 hat, hat keine Eltern. Er stammt direkt vom Kernel ab.} verfügt über
genau eine Parent-Prozeß-ID (PPID). Das ist die ID des Prozesses, der den
jeweiligen Prozeß erzeugt hat. Man spricht in diesem Zusammenhang tatsächlich
von Eltern- bzw. Kind-Prozessen.
Diese Zusammenhänge lassen sich sehr schön durch die Ausgabe des Kommandos
\texttt{pstree} oder \texttt{ps -efH} darstellen, letzteres zeigt auch gleich
die PIDs und die PPIDs an.
Wenn in einer Shell ein Kommando gestartet wird, ist es ein Kind dieser Shell.
Wird ein Skript gestartet, öffnet es sich seine eigene Shell (siehe
\ref{auswahl_der_shell}) und führt sich innerhalb dieser aus. Die Shell des
Skriptes ist dabei ein Kind der interaktiven Shell, die einzelnen Kommandos des
Skriptes sind Kinder der Skript-Shell.
Eine solche Shell-in-Shell-Umgebung wird `Subshell' genannt, dieser
Mechanismus~--~und somit auch der Begriff~--~tauchen immer wieder auf.
Wichtig in diesem Zusammenhang ist das Verständnis für die Vererbung zwischen
den beteiligten Prozessen. Wenn in einer Shell eine Variable definiert und
exportiert wird, existiert diese auch für die Kind-Prozesse. Gleiches gilt
beispielsweise für einen Verzeichnis-Wechsel. Umgekehrt gilt dies nicht: ein
Prozeß kann die Umgebung des Parent-Prozesses nicht verändern. Das geschieht
nicht zuletzt aus Sicherheitsgründen so.
Will man die Änderungen eines Skriptes übernehmen~--~beispielsweise wenn ein
Skript die Benutzerumgebung konfigurieren soll (.bashrc, .profile und
Konsorten)~--~muß das explizit angefordert werden. Dazu ruft man es mit einem
vorangestellten \texttt{source}\index{source=\texttt{source}} bzw. in der
Kurzform mit einem vorangestellten Punkt auf. Weiteres zu dem Thema findet sich
im Abschnitt \ref{source}.
Besonders muß man diesen Umstand im Hinterkopf behalten, wenn mit
Pipelines\index{Pipe} (siehe Abschnitt \ref{befehlsformen}) gearbeitet wird.
Dabei werden auch Kommandos in Subshells ausgeführt, was dann dazu führt daß
Variablen belegt werden die dann nach Ausführung der Pipeline plötzlich wieder
leer sind. Die Abschnitte \ref{subshellschleifen} und \ref{daten_hochreichen}
widmen sich diesem mitunter recht ärgerlichen Thema.
\index{Prozess|)}\index{Subshell|)}
\section{Programmablaufkontrolle}
Bei der Shell-Programmierung verfügt man über ähnliche Konstrukte wie bei anderen Programmiersprachen, um den Ablauf des Programms zu steuern. Dazu gehören Funktionsaufrufe, Schleifen, Fallunterscheidungen und dergleichen.\nopagebreak