diff --git a/beispiele.tex b/beispiele.tex index d3cca9e..d353770 100644 --- a/beispiele.tex +++ b/beispiele.tex @@ -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|)} diff --git a/schmutzige_tricks.tex b/schmutzige_tricks.tex index 8218468..50a198a 100644 --- a/schmutzige_tricks.tex +++ b/schmutzige_tricks.tex @@ -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 diff --git a/shell.tex b/shell.tex index 848084d..f26a997 100644 --- a/shell.tex +++ b/shell.tex @@ -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} diff --git a/tab_beisp_nullbefehl.tex b/tab_beisp_nullbefehl.tex deleted file mode 100644 index 7f7afab..0000000 --- a/tab_beisp_nullbefehl.tex +++ /dev/null @@ -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} diff --git a/werkzeugkasten.tex b/werkzeugkasten.tex index 485b39b..9b3902c 100644 --- a/werkzeugkasten.tex +++ b/werkzeugkasten.tex @@ -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}|)} diff --git a/wie_sieht_ein_shell_skript_aus.tex b/wie_sieht_ein_shell_skript_aus.tex index 2ae81ed..27d0246 100644 --- a/wie_sieht_ein_shell_skript_aus.tex +++ b/wie_sieht_ein_shell_skript_aus.tex @@ -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}}