|
|
|
@ -8,6 +8,11 @@ In der Shell stehen viele Mechanismen zur Verf
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
@ -35,6 +40,9 @@ 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.
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
Auf den meisten Systemen befindet sich im Pfad der Eintrag \texttt{\~{}/bin} bzw. \texttt{/home/benutzername/bin}, das bedeutet daß man Skripte die immer wieder benutzt werden sollen dort ablegen kann, so daß sie auch ohne eine Pfadangabe gefunden werden. Wie der Pfad genau aussieht kann man an der Shell durch Eingabe von \texttt{echo \$PATH}\index{\$PATH=\texttt{\$PATH}} herausfinden.
|
|
|
|
@ -44,7 +52,16 @@ Auf den meisten Systemen befindet sich im Pfad der Eintrag \texttt{\~{}/bin} bzw
|
|
|
|
|
|
|
|
|
|
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. Aber in der Programmierung von Shell-Skripten ist er von unschätzbarem Wert. So kann das Skript automatisch entscheiden, ob bestimmte Aktionen ausgeführt werden sollen, die von anderen Aktionen ab\-hän\-gen. Beispiele dazu sieht man bei der Beschreibung der Kommandos \texttt{if}\index{if=\texttt{if}} (\ref{if}), \texttt{case}\index{case=\texttt{case}} (\ref{case}), \texttt{while}\index{while=\texttt{while}} (\ref{while}) und \texttt{until}\index{until=\texttt{until}} (\ref{until}), sowie in dem Abschnitt über Befehlsformen (\ref{befehlsformen}).
|
|
|
|
|
Dieser Rückgabewert wird bei der interaktiven Benutzung der Shell nur selten
|
|
|
|
|
benutzt, da Fehlermeldungen direkt vom Benutzer abgelesen werden können. Aber
|
|
|
|
|
in der Programmierung von Shell-Skripten ist er von unschätzbarem Wert. So kann
|
|
|
|
|
das Skript automatisch entscheiden, ob bestimmte Aktionen ausgeführt werden
|
|
|
|
|
sollen, die von anderen Aktionen ab\-hän\-gen. Beispiele dazu sieht man bei der
|
|
|
|
|
Beschreibung der Kommandos \texttt{if}\index{if=\texttt{if}} (\ref{if}),
|
|
|
|
|
\texttt{case}\index{case=\texttt{case}} (\ref{case}),
|
|
|
|
|
\texttt{while}\index{while=\texttt{while}} (\ref{while}) und
|
|
|
|
|
\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}
|
|
|
|
@ -84,7 +101,18 @@ Die wichtigsten eingebauten Shell-Variablen sind:\nopagebreak
|
|
|
|
|
\section{Variablen-Substitution}\index{Variablen>-Substitution|(textbf}\index{Substitution|see{Variablen-Subst.}}\index{Variablen|(textbf}
|
|
|
|
|
\index{!==\texttt{!=}|(textbf}\index{\$\{Variable\}=\texttt{\$\{}\textsl{Variable}\texttt{\}}|(textbf}\index{\$\{Variable:-Wert\}=\texttt{\$\{}\textsl{Variable}\texttt{:-}\textsl{Wert}\texttt{\}}|(textbf}\index{\$\{Variable:=Wert\}=\texttt{\$\{}\textsl{Variable}\texttt{:=}\textsl{Wert}\texttt{\}}|(textbf}\index{\$\{Variable:?Wert\}=\texttt{\$\{}\textsl{Variable}\texttt{:?}\textsl{Wert}\texttt{\}}|(textbf}\index{\$\{Variable:+Wert\}=\texttt{\$\{}\textsl{Variable}\texttt{:+}\textsl{Wert}\texttt{\}}|(textbf}
|
|
|
|
|
|
|
|
|
|
Unter Variablen-Substitution versteht man verschiedene Methoden um die Inhalte von Variablen zu benutzen. Das umfaßt sowohl die einfache Zuweisung eines Wertes an eine Variable als auch einfache Möglichkeiten zur Fallunterscheidung. In den fortgeschritteneren Shell-Versionen (\texttt{bash}\index{Bourne-Again-Shell}, \texttt{ksh}\index{Korn-Shell}) existieren sogar Möglichkeiten, auf Substrings von Variableninhalten zuzugreifen. In der Standard-Shell benutzt man für einfache Aufgaben üblicherweise Tools wie \texttt{cut}, \texttt{basename}\index{basename=\texttt{basename}} oder \texttt{dirname}; komplexe Bearbeitungen erledigt der Stream-Editor \texttt{sed}\index{sed=\texttt{sed}}. Einleitende Informationen dazu finden sich im Kapitel über die Mustererkennung (\ref{mustererkennung}).
|
|
|
|
|
Unter Variablen-Substitution versteht man verschiedene Methoden um die Inhalte
|
|
|
|
|
von Variablen zu benutzen. Das umfaßt sowohl die einfache Zuweisung eines
|
|
|
|
|
Wertes an eine Variable als auch einfache Möglichkeiten zur Fallunterscheidung.
|
|
|
|
|
In den fortgeschritteneren Shell-Versionen
|
|
|
|
|
(\texttt{bash}\index{Bourne-Again-Shell}, \texttt{ksh}\index{Korn-Shell})
|
|
|
|
|
existieren sogar Möglichkeiten, auf Substrings von Variableninhalten
|
|
|
|
|
zuzugreifen. In der Standard-Shell benutzt man für einfache Aufgaben
|
|
|
|
|
üblicherweise Tools wie \texttt{cut},
|
|
|
|
|
\texttt{basename}\index{basename=\texttt{basename}} oder \texttt{dirname};
|
|
|
|
|
komplexe Bearbeitungen erledigt der Stream-Editor
|
|
|
|
|
\texttt{sed}\index{sed=\texttt{sed}}. Einleitende Informationen dazu finden
|
|
|
|
|
sich im Kapitel über die Mustererkennung (\ref{mustererkennung}).
|
|
|
|
|
|
|
|
|
|
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ß die \textsl{Variable} einen Wert enthalten. \nopagebreak
|
|
|
|
|
\LTXtable{\textwidth}{tab_variablen_substitution.tex}
|
|
|
|
@ -100,7 +128,11 @@ Die folgenden Mechanismen stehen in der Standard-Shell bereit, um mit Variablen
|
|
|
|
|
|
|
|
|
|
\index{' '=\texttt{' '}|see{Ticks}}\index{` `=\texttt{` `}|see{Backticks}}\index{\dq~\dq=\texttt{\dq~\dq}|see{Anführungszeichen}}\index{\textbackslash=\texttt{\textbackslash}|see{Backslash}}
|
|
|
|
|
|
|
|
|
|
Dies ist ein sehr schwieriges Thema, da hier mehrere ähnlich aussehende Zeichen völlig verschiedene Effekte bewirken. Unix unterscheidet allein zwischen drei verschiedenen Anführungszeichen. Das Quoten dient dazu, bestimmte Zeichen mit einer Sonderbedeutung vor der Shell zu `verstecken' um zu verhindern, daß diese expandiert (ersetzt) werden.
|
|
|
|
|
Dies ist ein sehr schwieriges Thema, da hier mehrere ähnlich aussehende Zeichen
|
|
|
|
|
völlig verschiedene Effekte bewirken. Die Bourne-Shell unterscheidet allein
|
|
|
|
|
zwischen drei verschiedenen Anführungszeichen. Das Quoten dient dazu, bestimmte
|
|
|
|
|
Zeichen mit einer Sonderbedeutung vor der Shell zu `verstecken' um zu
|
|
|
|
|
verhindern, daß diese expandiert (ersetzt) werden.
|
|
|
|
|
|
|
|
|
|
Die folgenden Zeichen haben eine spezielle Bedeutung innerhalb der Shell:\nopagebreak
|
|
|
|
|
\LTXtable{\textwidth}{tab_quoting_sonderzeichen.tex}
|
|
|
|
@ -123,8 +155,16 @@ Bei der Angabe von Dateinamen k
|
|
|
|
|
Die wichtigsten Meta-Zeichen sind:\nopagebreak
|
|
|
|
|
\LTXtable{\textwidth}{tab_metazeichen.tex}
|
|
|
|
|
|
|
|
|
|
\texttt{\~}, \texttt{\~{}}\textsl{name}, \texttt{\~{}+} und \texttt{\~{}-}
|
|
|
|
|
werden nicht von jeder Shell unterstützt.
|
|
|
|
|
|
|
|
|
|
\medskip\emph{Beispiele:}\nopagebreak
|
|
|
|
|
\LTXtable{\textwidth}{tab_beisp_metazeichen.tex}
|
|
|
|
|
|
|
|
|
|
Hier ist anzumerken, daß Hidden Files (Dateien, deren Name mit einem Punkt
|
|
|
|
|
beginnt) nicht durch ein einfaches \texttt{*} erfaßt werden, sondern nur durch
|
|
|
|
|
das Suchmuster \texttt{.*}.
|
|
|
|
|
|
|
|
|
|
\index{*=\texttt{*}|)}\index{?=\texttt{?}|)}\index{[abc]=\texttt{[}\textsl{abc}\texttt{]}|)}\index{[a-q]=\texttt{[}\textsl{a}\texttt{-}\textsl{q}\texttt{]}|)}\index{[!!abc]=\texttt{[!!}\textsl{abc}\texttt{]}|)}\index{Dateinamen|)}
|
|
|
|
|
\index{\~{}=\texttt{\~{}}|)}\index{\~{}name=\texttt{\~{}}\textsl{name}|)}\index{\~{}+=\texttt{\~{}+}|)}\index{\~{}-=\texttt{\~{}-}|)}
|
|
|
|
|
\index{Meta-Zeichen|)}
|
|
|
|
@ -145,10 +185,11 @@ TODO!!!
|
|
|
|
|
|
|
|
|
|
Man unterscheidet in der Shell-Programmierung zwischen den
|
|
|
|
|
Meta-Zeichen\index{Meta-Zeichen}, die bei der Bezeichnung von Dateinamen
|
|
|
|
|
eingesetzt werden (sogenanntes `Globbing'\index{Globbing}) und den Meta-Zeichen, die in
|
|
|
|
|
mehreren Programmen Verwendung finden, um z. B. Suchmuster zu definieren. Diese
|
|
|
|
|
Muster werden auch reguläre Ausdrücke (regular expression)\index{Regular
|
|
|
|
|
Expression|see{Regulärer Ausdruck}}\index{Expression|see{Regulärer
|
|
|
|
|
eingesetzt werden (sogenanntes `Globbing'\index{Globbing}) und den
|
|
|
|
|
Meta-Zeichen, die in mehreren Programmen Verwendung finden, um z. B. Suchmuster
|
|
|
|
|
zu definieren. Diese Muster werden auch reguläre Ausdrücke (regular
|
|
|
|
|
expression)\index{Regular Expression|see{Regulärer
|
|
|
|
|
Ausdruck}}\index{Expression|see{Regulärer
|
|
|
|
|
Ausdruck}}\index{Ausdruck|see{Regulärer Ausdruck}} genannt. Sie bieten
|
|
|
|
|
wesentlich mehr Möglichkeiten als die relativ einfachen Wildcards für
|
|
|
|
|
Dateinamen.
|
|
|
|
@ -198,9 +239,20 @@ Kommentare in der Shell beginnen immer mit dem Nummern-Zeichen (\verb\#\). Dabei
|
|
|
|
|
|
|
|
|
|
\subsection{Auswahl der Shell (\texttt{\#!})}\label{auswahl_der_shell}\index{\#!!=\texttt{\#!!}|see{Shell / Auswahl der\ldots}}\index{Shell>Auswahl der\ldots|(textbf}
|
|
|
|
|
|
|
|
|
|
In der ersten Zeile eines Shell-Skriptes sollte definiert werden, mit welcher Shell das Skript ausgeführt werden soll. Das System öffnet dann eine Subshell\index{Subshell} und führt das restliche Skript in dieser aus.
|
|
|
|
|
In der ersten Zeile eines Shell-Skriptes sollte definiert werden, mit welchem
|
|
|
|
|
Programm das Skript ausgeführt werden soll. Das System öffnet dann eine
|
|
|
|
|
Subshell\index{Subshell} und führt das restliche Skript in dieser aus.
|
|
|
|
|
|
|
|
|
|
Die Angabe erfolgt über eine Zeile in der Form \verb\#!/bin/sh\, wobei unter
|
|
|
|
|
\verb\/bin/sh\ die entsprechende Shell (in diesem Fall die Bourne-Shell) liegt.
|
|
|
|
|
Dieser Eintrag wirkt nur dann, wenn er in der ersten Zeile und der ersten
|
|
|
|
|
Spalte des Skripts steht.
|
|
|
|
|
|
|
|
|
|
Dieser Mechanismus ist bei der Bourne-Shell nicht vorhanden, er wurde mit den
|
|
|
|
|
moderneren Shells eingeführt um eben durch die Angabe von \verb\#!/bin/sh\ die
|
|
|
|
|
Bourne-Shell für die Ausführung von Shell-Skripten benutzen zu können. In der
|
|
|
|
|
Bourne-Shell wirkt das führende \verb\#\ als Kommentarzeichen.
|
|
|
|
|
|
|
|
|
|
Die Angabe erfolgt über eine Zeile in der Form \verb\#!/bin/sh\, wobei unter \verb\/bin/sh\ die entsprechende Shell (in diesem Fall die Bourne-Shell) liegt. Dieser Eintrag wirkt nur dann, wenn er in der ersten Zeile des Skripts steht.
|
|
|
|
|
\index{Shell>Auswahl der\ldots|)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -223,13 +275,17 @@ Die `gesourcte' Datei wird eingelesen und ausgef
|
|
|
|
|
\index{source=\texttt{source}|)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\subsection{Funktionen}\index{Funktion|(textbf}
|
|
|
|
|
\subsection{Funktionen}\label{funktionen}\index{Funktion|(textbf}
|
|
|
|
|
|
|
|
|
|
Es ist in der Shell auch möglich, ähnlich wie in einer `richtigen' Programmiersprache Funktionen zu deklarieren und zu benutzen. Da die Bourne-Shell (\verb\sh\) nicht über Aliase\index{Aliase} verfügt, können einfache Funktionen als Ersatz dienen.
|
|
|
|
|
|
|
|
|
|
Der Rückgabewert einer Funktion ist gleich dem Rückgabewert des letzten in der Funktion aufgerufenen Kommandos.
|
|
|
|
|
Der Rückgabewert einer Funktion ist gleich dem Rückgabewert des letzten in der
|
|
|
|
|
Funktion aufgerufenen Kommandos, es sei denn man gibt mittels
|
|
|
|
|
\verb\return\ (Siehe \ref{return}) explizit einen anderen Wert zurück.
|
|
|
|
|
|
|
|
|
|
\medskip\emph{Beispiel:} Die Funktion gibt die Anzahl der Dateien im aktuellen Verzeichnis zurück. Aufgerufen wird diese Funktion wie ein Befehl, also einfach durch die Eingabe von \verb\count\.\nopagebreak
|
|
|
|
|
\medskip\emph{Beispiel:} Die Funktion gibt die Anzahl der Dateien im aktuellen
|
|
|
|
|
Verzeichnis aus. Aufgerufen wird diese Funktion wie ein Befehl, also einfach
|
|
|
|
|
durch die Eingabe von \verb\count\.\nopagebreak
|
|
|
|
|
\LTXtable{\textwidth}{tab_beisp_funktionen.tex}
|
|
|
|
|
\index{Funktion|)}
|
|
|
|
|
|
|
|
|
@ -373,6 +429,17 @@ Die \texttt{exit}-Anweisung wird benutzt, um ein Skript zu beenden. Wenn der Par
|
|
|
|
|
\index{exit=\texttt{exit}|)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\subsection{return}\label{return}\index{return=\texttt{return}|(textbf}
|
|
|
|
|
|
|
|
|
|
Die Syntax der \texttt{return}-Anweisung lautet wie folgt:\nopagebreak
|
|
|
|
|
\LTXtable{\textwidth}{tab_return.tex}
|
|
|
|
|
|
|
|
|
|
Mittels \texttt{return} kann eine Funktion (siehe \ref{funktionen}) einen
|
|
|
|
|
bestimmten Wert zurückgeben. Anderenfalls wird der Exit-Code des letzten in der
|
|
|
|
|
Funktion ausgeführten Befehls zurückgegeben.
|
|
|
|
|
\index{return=\texttt{return}|)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\section{Befehlsformen}\label{befehlsformen}\index{Befehls>-formen|(textbf}
|
|
|
|
|
\index{\&=\texttt{\&}|(textbf}\index{;=\texttt{;}|(textbf}\index{( )=\texttt{( )}|(textbf}\index{\{ \}=\texttt{\{ \}}|(textbf}\index{Pipe|(textbf}\index{Backticks|(textbf}\index{\&\&=\texttt{\&\&}|(textbf}\index{!|!|=\texttt{!|!|}|(textbf}\index{Befehls>-substitution|(textbf}\index{Befehls>-folge|(textbf}\index{Befehls>-block|(textbf}
|
|
|
|
|
\index{!|=\texttt{!|}|see{Pipe}}\index{Substitution|see{Befehls-Subst.}}
|
|
|
|
|