Viele Aenderungen

This commit is contained in:
rschaten 2005-01-21 17:23:30 +00:00
parent 52635f366a
commit 68d30297e6
6 changed files with 209 additions and 84 deletions

View File

@ -16,10 +16,10 @@ Einfacher geht es, wenn wir uns ein kurzes Skript schreiben, das alle 30 Sekunde
\index{\^=\texttt{\^}}\index{Anführungszeichen}\index{Pipe}\index{grep=\texttt{grep}}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}}
\begin{lstlisting}
#!/bin/sh
until who | grep "^root "
do sleep 30
until who | grep "^root "; do
sleep 30
done
echo Big Brother is watching you!
echo "Big Brother is watching you!"
\end{lstlisting}
Das Skript führt also so lange das Kommando aus, bis die Ausführung erfolgreich
@ -42,10 +42,10 @@ Analog zum vorhergehenden Beispiel kann man auch ein Skript schreiben, das melde
\index{\^=\texttt{\^}}\index{Anführungszeichen}\index{grep=\texttt{grep}}\index{Pipe}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}}
\begin{lstlisting}
#!/bin/sh
while who | grep "^root "
do sleep 30
while who | grep "^root "; do
sleep 30
done
echo Die Katze ist aus dem Haus, Zeit, daß die Mäuse tanzen!
echo "Die Katze ist aus dem Haus, Zeit, daß die Mäuse tanzen!"
\end{lstlisting}
Die Schleife wird nämlich dann so lange ausgeführt, bis \texttt{grep}\index{grep=\texttt{grep}} einen Fehler (bzw. eine erfolglose Suche) zurückmeldet.
@ -245,18 +245,31 @@ echo "aflag=$aflag / Name = $name / Die Dateien sind $*"
\end{lstlisting}
\section{Fallensteller: Auf Traps
reagieren}\label{traps}\index{trap=\texttt{trap}|(}\index{Signal|(}
\section{Fallensteller: Auf Traps reagieren}\label{traps}\index{trap=\texttt{trap}|(}\index{Signal|(}
Ein laufendes Shell-Skript kann durch Druck auf die Interrupt-Taste (normalerweise \Ovalbox{CTRL}-\Ovalbox{C}) unterbrochen werden. Durch Druck auf diese Taste wird ein Signal an den entsprechenden Prozeß gesandt, das ihn bittet sich zu beenden. Dieses Signal heißt SIGINT (für SIGnal INTerrupt) und trägt die Nummer 2. Das kann ein kleines Problem darstellen, wenn das Skript sich temporäre Dateien angelegt hat, da diese nach der Ausführung nur noch unnötig Platz verbrauchen und eigentlich gelöscht werden sollten. Man kann sich sicher auch noch wichtigere Fälle vorstellen, in denen ein Skript bestimmte Aufgaben auf jeden Fall erledigen muß, bevor es sich beendet.
Ein laufendes Shell-Skript kann durch Druck auf die Interrupt-Taste
(normalerweise \Ovalbox{CTRL}-\Ovalbox{C}) unterbrochen werden. Durch Druck auf
diese Taste wird ein Signal an den entsprechenden Prozeß gesandt, das ihn
bittet sich zu beenden. Dieses Signal heißt SIGINT (für SIGnal INTerrupt) und
trägt die Nummer 2. Das kann ein kleines Problem darstellen, wenn das Skript
sich temporäre Dateien angelegt hat, da diese nach der Ausführung nur noch
unnötig Platz verbrauchen und eigentlich gelöscht werden sollten. Man kann
sich sicher auch noch wichtigere Fälle vorstellen, in denen ein Skript
bestimmte Aufgaben auf jeden Fall erledigen muß, bevor es sich beendet.
Es gibt eine Reihe weiterer Signale, auf die ein Skript reagieren kann. Alle sind in der Man-Page von \texttt{signal} beschrieben. Hier die wichtigsten:\nopagebreak
Es gibt eine Reihe weiterer Signale, auf die ein Skript reagieren kann. Alle
sind in der Man-Page von \texttt{signal} beschrieben. Hier die
wichtigsten:\nopagebreak
\LTXtable{\textwidth}{tab_signale.tex}
Wie löst man jetzt dieses Problem? Glücklicherweise verfügt die Shell über das \texttt{trap}-Kommando, mit dessen Hilfe man auf diese Signale reagieren kann. Die Anwendung soll in folgendem Skript beispielhaft dargestellt werden.
Wie löst man jetzt dieses Problem? Glücklicherweise verfügt die Shell über das
\texttt{trap}-Kommando, mit dessen Hilfe man auf diese Signale reagieren kann.
Die Anwendung soll in folgendem Skript beispielhaft dargestellt werden.
Das Skript soll eine komprimierte Textdatei mittels \texttt{zcat} in ein temporäres File entpacken, dieses mit \texttt{pg} seitenweise anzeigen und nachher wieder löschen.
Das Skript soll eine komprimierte Textdatei mittels \texttt{zcat} in ein
temporäres File entpacken, dieses mit \texttt{pg} seitenweise anzeigen und
nachher wieder löschen.
\index{!==\texttt{!=}}
\begin{lstlisting}
@ -266,7 +279,12 @@ temp=/tmp/zeige$$
\end{lstlisting}
Zunächst werden zwei Variablen belegt, die im weiteren Verlauf benutzt werden sollen. In \texttt{stat} wird der Wert abgelegt, den das Skript im Falle eines Abbruchs als Exit-Status zurückliefern soll. Die Variable \texttt{temp} enthält den Namen für eine temporäre Datei. Dieser setzt sich zusammen aus \texttt{/tmp/zeige} und der Prozeßnummer des laufenden Skripts. So soll sichergestellt werden, daß noch keine Datei mit diesem Namen existiert.
Zunächst werden zwei Variablen belegt, die im weiteren Verlauf benutzt werden
sollen. In \texttt{stat} wird der Wert abgelegt, den das Skript im Falle eines
Abbruchs als Exit-Status zurückliefern soll. Die Variable \texttt{temp} enthält
den Namen für eine temporäre Datei. Dieser setzt sich zusammen aus
\texttt{/tmp/zeige} und der Prozeßnummer des laufenden Skripts. So soll
sichergestellt werden, daß noch keine Datei mit diesem Namen existiert.
\index{Ticks}\index{!>\&=\texttt{!>\&}}\index{\$n=\texttt{\$}$n$}\index{Ticks}\index{Anführungszeichen}\index{Backticks}\index{basename=\texttt{basename}}
\begin{lstlisting}[firstnumber=last]
@ -275,7 +293,17 @@ trap 'echo "`basename $0`: Ooops..." 1>&2' 1 2 15
\end{lstlisting}
Hier werden die Traps definiert. Bei Signal 0 wird die temporäre Datei gelöscht und der Wert aus der Variable \texttt{stat} als Exit-Code zurückgegeben. Dabei wird dem \texttt{rm}-Kommando der Parameter\index{Parameter} \texttt{-f} mitgegeben, damit keine Fehlermeldung ausgegeben wird, falls die Datei (noch) nicht existiert. Dieser Fall tritt bei jedem Beenden des Skriptes auf, also sowohl bei einem normalen Ende, als auch beim Exit-Kommando, bei einem Interrupt oder bei einem Kill\index{kill=\texttt{kill}}. Der zweite Trap reagiert auf die Signale 1, 2 und 15. Das heißt, er wird bei jedem unnormalen Ende ausgeführt. Er gibt eine entsprechende Meldung auf die Standard-Fehlerausgabe (\ref{datenstrom}) aus. Danach wird das Skript beendet, und der erste Trap wird ausgeführt.
Hier werden die Traps definiert. Bei Signal 0 wird die temporäre Datei gelöscht
und der Wert aus der Variable \texttt{stat} als Exit-Code zurückgegeben. Dabei
wird dem \texttt{rm}-Kommando der Parameter\index{Parameter} \texttt{-f}
mitgegeben, damit keine Fehlermeldung ausgegeben wird, falls die Datei (noch)
nicht existiert. Dieser Fall tritt bei jedem Beenden des Skriptes auf, also
sowohl bei einem normalen Ende, als auch beim Exit-Kommando, bei einem
Interrupt oder bei einem Kill\index{kill=\texttt{kill}}. Der zweite Trap
reagiert auf die Signale 1, 2 und 15. Das heißt, er wird bei jedem unnormalen
Ende ausgeführt. Er gibt eine entsprechende Meldung auf die
Standard-Fehlerausgabe (\ref{datenstrom}) aus. Danach wird das Skript beendet,
und der erste Trap wird ausgeführt.
\index{\$\#=\texttt{\$\#}}\index{!==\texttt{!=}}\index{!>=\texttt{!>}}\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{case=\texttt{case}}
\begin{lstlisting}[firstnumber=last]
@ -287,7 +315,14 @@ case $# in
\end{lstlisting}
Jetzt kommt die eigentliche Funktionalität des Skriptes: Das \texttt{case}-Kommando (\ref{case}) testet die Anzahl der übergebenen Parameter\index{Parameter}. Wenn genau ein Parameter\index{Parameter} übergeben wurde, entpackt \texttt{zcat} die Datei, die im ersten Parameter\index{Parameter} angegeben wurde, in die temporäre Datei. Dann folgt die Seitenweise Ausgabe mittels \texttt{pg}. Nach Beendigung der Ausgabe wird der Status in der Variablen auf 0 gesetzt, damit beim Skriptende der korrekte Exit-Code zurückgegeben wird.
Jetzt kommt die eigentliche Funktionalität des Skriptes: Das
\texttt{case}-Kommando (\ref{case}) testet die Anzahl der übergebenen
Parameter\index{Parameter}. Wenn genau ein Parameter\index{Parameter} übergeben
wurde, entpackt \texttt{zcat} die Datei, die im ersten
Parameter\index{Parameter} angegeben wurde, in die temporäre Datei. Dann folgt
die Seitenweise Ausgabe mittels \texttt{pg}. Nach Beendigung der Ausgabe wird
der Status in der Variablen auf 0 gesetzt, damit beim Skriptende der korrekte
Exit-Code zurückgegeben wird.
\index{!>\&=\texttt{!>\&}}\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{Backticks}\index{basename=\texttt{basename}}
\begin{lstlisting}[firstnumber=last]
@ -296,7 +331,9 @@ esac
\end{lstlisting}
Wenn \texttt{case} eine andere Parameterzahl feststellt, wird eine Meldung mit der Aufrufsyntax auf die Standard-Fehlerausgabe geschrieben.
Wenn \texttt{case} eine andere Parameterzahl feststellt, wird eine Meldung mit
der Aufrufsyntax auf die Standard-Fehlerausgabe geschrieben.
\index{trap=\texttt{trap}|)}\index{Signal|)}

View File

@ -42,7 +42,7 @@ werden um wieder entpackt zu werden.
Ein Beispiel verdeutlicht diese Kopier-Fähigkeit:
\texttt{tar cf - . | ( cd /tmp/backup; tar xf - )}
\lstinline_tar cf - . | ( cd /tmp/backup; tar xf - )_
Hier wird zunächst der Inhalt des aktuellen Verzeichnisses `verpackt'. Das
Resultat wird an die Standard-Ausgabe geschrieben. Auf der Empfängerseite der
@ -57,9 +57,13 @@ Am Ziel-Ort finden sich jetzt die gleichen Dateien wie am Quell-Ort.
Das ließe sich lokal natürlich auch anders lösen. Man könnte erst ein Archiv
erstellen, das dann an anderer Stelle wieder auspacken. Nachteil: Es muß
genügend Platz für das Archiv vorhanden sein. Denkbar wäre auch ein in den Raum
gestelltes \texttt{cp -Rp * /tmp/backup}. Allerdings fehlen einem dabei
mitunter nützliche \texttt{tar}-Optionen\footnote{Mit \texttt{-l} verläßt
\texttt{tar} beispielsweise nicht das File-System. Nützlich wenn eine Partition
gestelltes
\lstinline_cp -Rp * /tmp/backup_
Allerdings fehlen einem dabei mitunter nützliche
\texttt{tar}-Optionen\footnote{Mit \texttt{-l} verläßt \texttt{tar}
beispielsweise nicht das File-System. Nützlich wenn nur eine Partition
gesichert werden soll.}, und die oben erwähnte Brücke wäre mit einem reinen
\texttt{cp} nicht möglich.
@ -69,14 +73,14 @@ nur unter Vorsicht einsetzen!) schlagen die Br
dort wird entweder gepackt und versendet oder quasi die Subshell gestartet und
gelesen. Das sieht wie folgt aus:
\texttt{ssh 192.168.2.1 tar clf - / | (cd /mnt/backup; tar xf - )}
\lstinline_ssh 192.168.2.1 tar clf - / | (cd /mnt/backup; tar xf - )_
Hier wird auf einem entfernten Rechner die Root-Partition verpackt, per SSH in
das lokale System geholt und lokal im Backup-Verzeichnis entpackt.
Der Weg in die andere Richtung ist ganz ähnlich:
\texttt{tar cf - datei.txt | ssh 192.168.2.1 \dq(mkdir -p \$PWD ;cd \$PWD; tar xf -)\dq}
\lstinline_tar cf - datei.txt | ssh 192.168.2.1 "(mkdir -p $PWD ;cd $PWD; tar xf -)"_
Hier wird die Datei verpackt und versendet. Eine Besonderheit gegenüber dem
vorigen Beispiel bestehtdarin, daß das Zielverzeichnis bei Bedarf erstellt

View File

@ -15,6 +15,8 @@
headsepline, % Trennlinie unter die Kopfzeile
pointlessnumbers, % Keine Punkte hinter den
% Gliederungsnummern
% halfparskip, % Abstände zwischen den Absätzen, statt
% Einrückung der ersten Zeile
% draft, % Entwurfsmodus
final, % Release-Modus
twoside % Doppelseitig, für Buch
@ -49,9 +51,11 @@
\lstset{
extendedchars=true,
backgroundcolor=\color[gray]{0.95},
basicstyle=\ttfamily\scriptsize,
%basicstyle=\ttfamily\scriptsize,
basicstyle=\ttfamily\footnotesize,
numbers=left,
numberstyle=\tiny,
%numberstyle=\tiny,
numberstyle=\scriptsize,
stepnumber=2,
numbersep=5pt
}
@ -104,6 +108,32 @@
\newpage
\thispagestyle{empty} % eine Leerseite
~\vfill
%\fboxsep 1.36mm
%\definecolor{g1}{gray}{0.92}
%\newsavebox{\syntaxbox}
%\newenvironment{sybox}
%{\begin{lrbox}{\syntaxbox}
%\begin{minipage}{12.5cm}}
%{\end{minipage}
%\end{lrbox}
%{\fcolorbox{g1}{g1}
%{\parbox{12.5cm}{\usebox{\syntaxbox}\hfill\hbox{}}}}}
%
%\begin{sybox}
%Syntaxbox, in der Sonderzeichen wie \verb?%~^? dargestellt werden können.
%
%Dieses Dokument ist entstanden, weil ich für mich selbst eine kompakte
%Übersicht zu diesem Thema haben wollte. Ich beabsichtige nicht, damit in
%irgendeiner Form Kommerz zu machen. Ich stelle es frei zur Verfügung, in der
%Hoffnung, daß andere Leute daraus vielleicht einen Nutzen ziehen können.
%\textbf{Aber ich übernehme keine Garantie für die Korrektheit der hier
%dargestellten Dinge.} Mit der Formulierung \textsl{`daraus vielleicht einen
%Nutzen ziehen können'} meine ich nicht, daß dieses Dokument~--~oder Teile
%daraus~--~verkauft werden darf. \textbf{Dieses Dokument darf nur kostenlos
%weitergegeben werden.}
%\end{sybox}
\footnotesize
Copyright \copyright{} 2000-2005 Ronald Schaten (ronald@schatenseite.de)\bigskip
@ -139,7 +169,11 @@ chronologischer Reihenfolge ihres Eingreifens):
Und ich bitte alle Leser, auf eventuelle Fehler zu achten und mich darauf
aufmerksam zu machen. Auch abgesehen davon freue ich mich über jede
Rückmeldung.
Rückmeldung.\bigskip
Dieses Dokument entstand unter Verwendung von Linux, vim und \LaTeX. Dank an
deren Entwickler.
\normalsize
\newpage
\pagenumbering{roman}

View File

@ -1,16 +0,0 @@
% $Id$
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{if who | grep \$1 > /dev/null~~\# who: Liste der Benutzer}\index{Pipe}\index{\$n=\texttt{\$}$n$}\index{!>=\texttt{!>}}\index{who=\texttt{who}}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\# grep: Suche nach Muster}} \\
\multicolumn{2}{|X|}{\texttt{then :~~~~~~~~~~~~~~~~~~~~~~~~\# tut nichts}} \\
\multicolumn{2}{|X|}{\texttt{~else echo \dq Benutzer \$1 ist nicht angemeldet\dq}\index{Anführungszeichen}} \\
\multicolumn{2}{|X|}{\texttt{fi}} \\
\end{longtable}

View File

@ -240,8 +240,8 @@ awk '
print $2;
}' datei.txt
# Alternativ können die Kommandos auch in eine eigene Datei gespeichert und
# über den Parameter -f eingebunden werden:
# Alternativ können die Kommandos auch in eine eigene Datei gespeichert
# und über den Parameter -f eingebunden werden:
awk -f script.awk datei.txt
\end{lstlisting}
@ -313,8 +313,8 @@ Hier ein paar Einfache Beispiele f
# Datensätze mit mehr als zwei Feldern auswählen:
NF > 2
# Das dritte und das zweite Feld jeder Zeile ausgeben, deren erstes Feld den
# String 'WICHTIG' enthält:
# Das dritte und das zweite Feld jeder Zeile ausgeben, deren erstes Feld
# den String 'WICHTIG' enthält:
$1 ~ /WICHTIG/ { print $3, $2 }
# Die Vorkommen von 'muster' zählen, und deren Anzahl ausgeben:
@ -328,19 +328,20 @@ length($0) < 23
# enthalten:
NF == 7 && /^Name:/
# Alle Felder der Eingabedaten zeilenweise in umgekehrter Reihenfolge ausgeben:
# Alle Felder der Eingabedaten zeilenweise in umgekehrter Reihenfolge
# ausgeben:
{
for (i = NF; i >= 1; i--)
print $i
}
# Die Größe aller TeX-Dateien addieren, die Summe in kB umrechnen und ausgeben,
# verarbeitet die Ausgabe von 'ls -l':
# Die Größe aller TeX-Dateien addieren, die Summe in kB umrechnen und
# ausgeben, verarbeitet die Ausgabe von 'ls -l':
/.*tex/ { summe += $5 }
END { summe /= 1024; print "Die Größe aller TeX-Files beträgt", summe, "kB" }
END { summe /= 1024; print "Die Größe aller TeX-Files:", summe, "kB" }
# Pipe-Separierte Liste aller gemounteten Partitionen und derer Füllstände
# ausgeben, verarbeitet die Ausgabe von 'df':
# Pipe-Separierte Liste aller gemounteten Partitionen und derer
# Füllstände ausgeben, verarbeitet die Ausgabe von 'df':
BEGIN { OFS="|" }
/^\/dev\// { print $1,$5 }
@ -705,15 +706,20 @@ hier ein paar praktische Beispiele:
\begin{lstlisting}
# Suche alle Einträge in bzw. unter dem aktuellen Verzeichnis:
find .
# Suche alle normalen Dateien mit der Endung txt unter /home:
find /home -type f -name \*.txt
# Suche alle Einträge außer symbolischen Links, in die jeder schreiben darf:
# Suche alle Einträge außer symbolischen Links, in die jeder schreiben
# darf:
find / \! -type l -perm 777
# Suche alle Dateien unter dem Homeverzeichnis, deren Größe 10000000 Bytes
# übersteigt und gib sie ausführlich aus:
# Suche alle Dateien unter dem Homeverzeichnis, deren Größe 10000000
# Bytes übersteigt und gib sie ausführlich aus:
find ~ -size +10000000c -exec ls -l {} \;
# Suche alle Einträge im Homeverzeichnis, die innerhalb der letzten zwei Tage
# geändert wurden:
# Suche alle Einträge im Homeverzeichnis, die innerhalb der letzten zwei
# Tage geändert wurden:
find ~ -mtime -2
\end{lstlisting}
@ -790,7 +796,8 @@ Es gibt verschiedene Wege, das Signal abzusetzen. Welchen man w
Geschmackssache. Hier ein paar Beispiele:
\begin{lstlisting}
# Die folgenden Befehle sind gleichwertig. Alle senden ein HUP an Prozeß-ID 42:
# Die folgenden Befehle sind gleichwertig. Alle senden ein HUP an
# Prozeß-ID 42:
kill -1 42
kill -HUP 42
kill -SIGHUP 42
@ -798,7 +805,8 @@ kill -s 1 42
kill -s HUP 42
kill -s SIGHUP 42
# virtueller Selbstmord: Alle Prozesse umbringen, die man umbringen kann:
# virtueller Selbstmord:
# Alle Prozesse umbringen, die man umbringen kann:
kill -9 -1
# SIGTERM an mehrere Prozesse senden:
@ -1073,8 +1081,8 @@ ps -ely
ps ax
ps axu
# Prozeßbaum ausgeben. Das ist in Skripten weniger Sinnvoll, wird hier aber
# angegeben weil es so eine praktische Funktion ist... :-)
# Prozeßbaum ausgeben. Das ist in Skripten weniger Sinnvoll, wird hier
# aber angegeben weil es so eine praktische Funktion ist... :-)
ps -ejH
ps axjf
@ -1229,12 +1237,12 @@ kommando1 | sed 's/alt/neu/' | kommando2
# Aufruf mit einer zu bearbeitenden Datei:
sed 's/alt/neu/' datei.txt
# Wenn mehr als ein Kommando ausgeführt werden soll, muß der Parameter -e
# verwendet werden:
# Wenn mehr als ein Kommando ausgeführt werden soll, muß der Parameter
# -e verwendet werden:
sed -e 's/alt/neu/' -e '/loeschen/d' datei.txt
# Man kann auch mehrere Kommandos mit einem -e aufrufen, wenn sie durch ein
# Semikolon getrennt werden:
# Man kann auch mehrere Kommandos mit einem -e aufrufen, wenn sie durch
# ein Semikolon getrennt werden:
sed 's/alt/neu/; /loeschen/d' datei.txt
# In einem Skript kann das Kommando auch über mehrere Zeilen gehen:
@ -1242,8 +1250,8 @@ sed '
s/alt/neu/
/loeschen/d' datei.txt
# Alternativ können die Kommandos auch in eine eigene Datei gespeichert und
# über den Parameter -f eingebunden werden:
# Alternativ können die Kommandos auch in eine eigene Datei gespeichert
# und über den Parameter -f eingebunden werden:
sed -f script.sed datei.txt
\end{lstlisting}
@ -1330,10 +1338,12 @@ sed 's/rot/blau/' # Ersetzt nur das erste Vorkommen in jeder Zeile
sed 's/rot/blau/4' # Ersetzt nur das vierte Vorkommen in jeder Zeile
sed 's/rot/blau/g' # Ersetzt nur jedes Vorkommen in jeder Zeile
# 'rot' durch 'blau' ersetzen, aber NUR in Zeilen die auch 'gelb' enthalten:
# 'rot' durch 'blau' ersetzen, aber NUR in Zeilen die auch 'gelb'
# enthalten:
sed '/gelb/s/rot/blau/g'
# 'rot' durch 'blau' ersetzen, AUSSER in Zeilen die auch 'gelb' enthalten:
# 'rot' durch 'blau' ersetzen, AUSSER in Zeilen die auch 'gelb'
# enthalten:
sed '/gelb/!s/rot/blau/g'
# 'rosa', 'hellrot' und 'magenta' durch 'pink' ersetzen:
@ -1344,9 +1354,10 @@ gsed 's/rosa\|hellrot\|magenta/pink/g' # nur in GNU sed
# lies: 'ersetze jeden Zeilenanfang durch fünf Leerzeichen'
sed 's/^/ /'
# Führende Blanks (Leerzeichen, Tabulatoren) von den Zeilenanfängen löschen:
# ACHTUNG: An Stelle des \t muß der Tabulator gedrückt werden, die Darstellung
# als \t versteht nicht jedes sed!
# Führende Blanks (Leerzeichen, Tabulatoren) von den Zeilenanfängen
# löschen:
# ACHTUNG: An Stelle des \t muß der Tabulator gedrückt werden, die
# Darstellung als \t versteht nicht jedes sed!
sed 's/^[ \t]*//'
# Schliessende Blanks vom Zeilenende löschen, siehe oben:
@ -1612,6 +1623,30 @@ Kommando gibt zm Beispiel eine Fehlermeldung aus wenn sein Skript ein Signal 1
Die Zeile ist dem Beispiel aus Abschnitt \ref{traps} entnommen, dort findet
sich auch nochmal eine ausführliche Erklärung.
Ein weiterer nützlicher Einsatz für \texttt{trap} ist es, Signale zu
ignorieren. Das kann gewünscht sein, wenn eine Folge von Kommandos in einem
Skript auf keinen Fall unterbrochen werden darf. Um zu verhindern daß ein
\Ovalbox{CTRL}-\Ovalbox{C} des Benutzers das Skript beendet wird folgendes
Konstrukt eingesetzt:
\begin{lstlisting}
trap '' 2 # Signal 2 ist Ctrl-C, jetzt deaktiviert.
kommando1
kommando2
kommando3
trap 2 # Reaktiviert Ctrl-C
\end{lstlisting}
Vielleicht wäre es aber auch dem Benutzer gegenüber freundlicher, auf das
entkräftete Signal hinzuweisen:
\lstinline|trap 'echo "Ctrl-C ist ausser Kraft."' 2|
Eine Sonderbehandlung macht die Shell, wenn als Signal \texttt{DEBUG} angegeben
wird. Dann wird nach jedem ausgeführten Kommando der Trap ausgelöst. Dieses
Feature wird wie der Name schon erahnen läßt zum Debuggen benutzt, ein Beispiel
findet sich in Abschnitt \ref{fehlersuche}.
\index{trap=\texttt{trap}|)}

View File

@ -54,7 +54,7 @@ da
kann man an der Shell durch Eingabe von \lstinline/echo $PATH/\index{\$PATH=\texttt{\$PATH}} herausfinden.
\section{Fehlersuche}
\section{Fehlersuche}\label{fehlersuche}\index{Fehlersuche|(}\index{debuggen|(}
Es gibt für Shell-Skripte keine wirklichen Debugger, aber trotzdem verfügt man
über einige bewährte Methoden zum Aufspüren von Fehlern:
@ -86,6 +86,18 @@ Aufruf
Zeile vor der Ausführung aus, allerdings im Gegensatz zu \texttt{-x} nicht in
der expandierten sondern in der vollen Form.
\item \texttt{set -e}: Alle gängigen Shell-Kommandos liefern einen
Rückgabewert, der Auskunft über Erfolg oder Mißerfolg gibt (siehe Abschnitt
\ref{exitcode}). Normalerweise liegt es beim Programmierer, diese Werte zu
interpretieren. Setzt man aber mit dem Schalter \texttt{-e} den sogenannten
errexit-Modus, beendet die Shell das Skript sobald ein Kommando sich mit einem
Rückgabewert ungleich 0 beendet.
Ausnahmen gibt es lediglich, wenn das betroffene Kommando in ein Konstrukt
wie \texttt{while}, \texttt{until} oder \texttt{if} eingebunden ist. Auch wenn
der Rückgabewert mittels \texttt{\&\&} oder \texttt{||} verarbeitet wird,
beendet sich die Shell nicht.
\item System-Log: Für das direkte Debuggen ist dieser Weg weniger geeignet,
aber gerade in unbeobachtet laufenden Skripten sollte man unerwartete Zustände
oder besondere Ereignisse im System-Log festhalten. Dies geschieht mit dem
@ -98,12 +110,22 @@ eine l
Ruhe analysiert werden. Das Kommando wird in Abschnitt \ref{script}
beschrieben.
TODO: Debuggen
%http://localhost/~rschaten/doku/abs-guide/debugging.html#FTN.AEN14050
%-> trapping signals
\item \texttt{tee}: Wenn Ausgaben eines Kommandos durch den Filter \texttt{tee}
geschoben werden, können sie in einer Datei mitgeschrieben werden. Auch diese
Variante bietet einen streßfreien Blick auf unter Umständen sehr lange und
komplexe Ausgaben. Abschnitt \ref{tee} gibt weitere Hinweise zu dem Kommando.
\item Variablen `tracen': Das Kommando \texttt{trap} (Abschnitt \ref{trap})
reagiert auf Signale. Die Shell erzeugt nach jedem Kommando das Signal DEBUG,
so daß mit dem folgenden Kommando dafür gesorgt werden kann, daß der Inhalt
einer Variablen nach jedem Kommando ausgegeben wird:
\lstinline|trap 'echo "Trace> \$var = \"$var\""' DEBUG|
\end{itemize}
\index{Fehlersuche|)}\index{debuggen|)}
\section{Rückgabewerte}\label{exitcode}\index{Rückgabewert|(textbf}\index{Exit-Code|see{Rückgabewert}}\index{Exit-Status|see{Rückgabewert}}
@ -286,11 +308,16 @@ Die folgenden Zeichen k
\index{Quoting|)}
\section{Meta-Zeichen}\index{Meta-Zeichen|(textbf}\index{Wildcards|see{Metazeichen}}\index{Joker-Zeichen|see{Metazeichen}}\index{Platzhalter|see{Metazeichen}}\label{metazeichen}
\section{Meta-Zeichen}\index{Meta-Zeichen|(textbf}\index{Wildcards|see{Metazeichen}}\index{Joker-Zeichen|see{Metazeichen}}\index{Platzhalter|see{Metazeichen}}\index{Globbing|see{Metazeichen}}\label{metazeichen}
\index{*=\texttt{*}|(textbf}\index{?=\texttt{?}|(textbf}\index{[abc]=\texttt{[}\textsl{abc}\texttt{]}|(textbf}\index{[a-q]=\texttt{[}\textsl{a}\texttt{-}\textsl{q}\texttt{]}|(textbf}\index{[!!abc]=\texttt{[!!}\textsl{abc}\texttt{]}|(textbf}\index{Dateinamen|(textbf}
\index{\~{}=\texttt{\~{}}|(textbf}\index{\~{}name=\texttt{\~{}}\textsl{name}|(textbf}\index{\~{}+=\texttt{\~{}+}|(textbf}\index{\~{}-=\texttt{\~{}-}|(textbf}
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.
Bei der Angabe von Dateinamen können eine Reihe von
Meta-Zeichen\footnote{Meta-Zeichen werden auch Wildcards, Joker-Zeichen oder
Platzhalter genannt. Meint man die Expansion der Meta-Zeichen zu Dateinamen ist
auch von `Globbing' die Rede.} verwendet werden, um mehrere Dateien
gleichzeitig anzusprechen oder um nicht den vollen Dateinamen ausschreiben zu
müssen.
Die wichtigsten Meta-Zeichen sind:\nopagebreak
\LTXtable{\textwidth}{tab_metazeichen.tex}
@ -317,10 +344,9 @@ das Suchmuster \texttt{.*}.
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
eingesetzt werden 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
@ -491,9 +517,14 @@ der Bourne-Shell wirkt das f
Dieser Befehl tut nichts, außer den Status 0 zurückzugeben. Er wird benutzt, um Endlosschleifen\index{Endlosschleife} zu schreiben (siehe unter \ref{while}), oder um leere Blöcke in \texttt{if}- oder \texttt{case}-Konstrukten\index{if=\texttt{if}}\index{case=\texttt{case}} möglich zu machen.
\medskip\emph{Beispiel:} Prüfen, ob jemand angemeldet ist:\nopagebreak
\LTXtable{\textwidth}{tab_beisp_nullbefehl.tex}
\index{Null-Befehl|)}
\begin{lstlisting}
if who | grep $1 > /dev/null; then # who: Liste der Benutzer
# grep: Suche nach Muster
: # tut nichts
else
echo "Benutzer $1 ist nicht angemeldet"
fi
\end{lstlisting}
\subsection{Source (\texttt{.})}\label{source}\index{source=\texttt{source}|(textbf}\index{.=\texttt{.}|see{source}}