Compare commits

..

56 Commits

Author SHA1 Message Date
rschaten
1080ae9a51 URL repariert. 2006-02-15 14:50:53 +00:00
rschaten
7cfcc66ec1 Zitat eingefuegt 2006-01-10 10:42:48 +00:00
rschaten
1bdc17acfc Version 2.0.1, leichte Umstellung der Reihenfolge 2006-01-10 10:27:37 +00:00
rschaten
84abd69c4a Neuer Abschnitt: Auf Tastendruck warten 2005-10-04 10:58:56 +00:00
rschaten
50ed10a887 Version 2.0.0 2005-04-29 15:00:06 +00:00
rschaten
9978ac040b Version 2.0.0 2005-04-29 14:55:09 +00:00
rschaten
577cdbfcd1 Kleine Verbesserungen, neue Kommandos exec und type. 2005-02-22 21:30:40 +00:00
rschaten
f72918f75d Fehlerkorrektur 2005-02-08 18:51:23 +00:00
rschaten
75357d86bc Lizenz eingesetzt 2005-02-03 22:53:26 +00:00
rschaten
5b9829acef Viele Neuerungen 2005-02-03 22:24:18 +00:00
rschaten
82d1e3e470 Viele Aenderungen, Tabellen durch Syntax-Boxen ausgetauscht, neues Kapitel: date 2005-01-28 10:07:07 +00:00
rschaten
68d30297e6 Viele Aenderungen 2005-01-21 17:23:30 +00:00
rschaten
52635f366a Unnoetigen TODO entfernt 2005-01-14 16:30:48 +00:00
rschaten
5fdc537aa9 Diverse Aenderungen. 2005-01-14 16:27:08 +00:00
rschaten
483c60f1db Tar-Bruecke eingebaut 2005-01-06 10:48:37 +00:00
rschaten
9e6a3f8e7a Neues AWK-Beispiel zugefuegt 2004-12-13 10:01:57 +00:00
rschaten
464f0bcf77 Umformatiert 2004-12-10 14:38:03 +00:00
rschaten
15af99f29e Viele Aenderungen 2004-12-02 13:54:06 +00:00
rschaten
c0e556e25d Viele nderungen 2004-11-26 15:40:47 +00:00
rschaten
fe58ca9711 Viele grosse Aenderungen 2004-11-19 12:09:34 +00:00
rschaten
14dec49967 Viele ueberarbeitungen 2004-11-12 12:07:32 +00:00
rschaten
7eea8ed0e9 Grundlegende Ueberarbeitung 2004-11-05 16:20:53 +00:00
rschaten
c6e06f8072 Struktur umgestellt 2004-10-28 15:44:41 +00:00
rschaten
b7c54658b2 kaputten Link repariert 2003-12-31 11:57:43 +00:00
rschaten
44b7aa5f9b ID-Keyword in das Vorwort eingebaut 2003-04-11 15:14:35 +00:00
rschaten
78f93544bd Keywords zugefuegt 2003-04-11 15:05:25 +00:00
rschaten
2225e88484 Kai Thoene in die Credits aufgenommen 2002-08-02 11:27:51 +00:00
rschaten
136b632f8f Zufallszahlen hinzugefgt 2002-04-12 11:55:28 +00:00
rschaten
ff78ec65e4 Copyright auf 2000-2002 gesetzt 2002-04-10 09:51:27 +00:00
rschaten
bd36939a90 ps-Trick bei grep eingefgt 2002-04-10 09:50:30 +00:00
rschaten
a7f9f8ccdd TODO fr printf eingefgt 2002-04-09 09:44:58 +00:00
rschaten
31924e5ab5 Subshell-Schleifen vermeiden 2002-03-25 13:48:40 +00:00
rschaten
5c655b4df2 Semikolon zu der Befehlsform { xxx; } hinzugefgt 2002-03-25 08:57:29 +00:00
rschaten
f0daf0d532 dcous hinzugefgt 2002-03-22 16:38:07 +00:00
rschaten
7a676d4647 Dateien gleichzeitig lesen und schreiben 2002-03-22 16:34:33 +00:00
rschaten
3582465121 chpasswd umformatiert 2002-03-22 16:33:28 +00:00
rschaten
c1380f16a2 Falk Friedrich zu der Danke-Liste zugefgt 2002-03-22 16:00:59 +00:00
rschaten
80a7166150 Beschreibung zu until... korrigiert 2002-03-22 15:31:40 +00:00
rschaten
dc7eb4bedf chpasswd hinzugefgt 2002-03-22 15:21:32 +00:00
rschaten
516e0c1707 initiale Version 2002-02-25 16:24:08 +00:00
rschaten
f921275c10 Label fr IFS hinzugefgt 2002-02-25 16:19:18 +00:00
rschaten
cff6123cad Pipes verndert 2002-02-25 16:17:18 +00:00
rschaten
ccc6061c3f Abschnitt 'Pfade und Dateien' eingefgt 2001-10-09 18:50:47 +00:00
rschaten
b523791d1b read-Kommando hinzugefgt 2001-10-09 07:50:02 +00:00
rschaten
029828ff41 PDF als Standardformat eingerichtet 2001-10-09 07:09:33 +00:00
rschaten
a4c627a1a5 Beispiel zu 'Datei zeilenweise bearbeiten' konstruiert 2001-09-25 18:25:29 +00:00
rschaten
90a49f0f52 Klammer-Expansion zugefgt 2001-09-25 17:48:00 +00:00
rschaten
4a00e0290b Beschreibungen fr head und tail 2001-09-24 16:58:06 +00:00
rschaten
e0271effdb nderungsvorschlge von Kai Thne eingebaut 2001-09-24 16:39:49 +00:00
rschaten
06193ffb55 Beschreibung von echo und cat
tail hinzugefgt
2001-07-02 16:53:41 +00:00
rschaten
d293f41934 nderungen nach Problemen mit der Benennung 2001-07-02 16:38:46 +00:00
rschaten
3f0e20007f neu erstellt 2001-07-02 16:34:58 +00:00
rschaten
85b9643684 gelscht (wegen umbenennung) 2001-07-02 16:34:21 +00:00
rschaten
27e5af6fbe Neu erstellt 2001-07-02 16:29:20 +00:00
rschaten
e2e810895b script hinzugefgt 2001-07-02 15:32:33 +00:00
rschaten
02678fcea4 Zeilenumbrche gendert 2001-07-02 13:02:30 +00:00
77 changed files with 4172 additions and 711 deletions

View File

@ -134,6 +134,10 @@ ifndef DVIVIEWER
DVIVIEWER=xdvi DVIVIEWER=xdvi
endif endif
ifndef PDFVIEWER
PDFVIEWER=acroread
endif
ifndef LATEX2HTML ifndef LATEX2HTML
LATEX2HTML=latex2html LATEX2HTML=latex2html
endif endif
@ -271,21 +275,6 @@ TEXFILES=$(wildcard *.tex)
touch $*.ind; \ touch $*.ind; \
fi fi
latex:
# Below the 'true' is included to prevent unnecessarily many errors.
@if [ -n "${LATEXTARGET}" ]; then \
$(MAKE) ${LATEXTARGET}.dvi; \
true; \
else \
if [ `ls *.tex | wc -l` = "1" ]; then \
$(MAKE) `basename \`ls *.tex\` .tex`.dvi; \
true; \
else \
$(MAKE) `echo $$PWD|tr '/' '\n'|tail -1`.dvi; \
true; \
fi; \
fi
pdflatex: pdflatex:
# Below the 'true' is included to prevent unnecessarily many errors. # Below the 'true' is included to prevent unnecessarily many errors.
@if [ -n "${LATEXTARGET}" ]; then \ @if [ -n "${LATEXTARGET}" ]; then \
@ -301,12 +290,27 @@ pdflatex:
fi; \ fi; \
fi fi
latex:
# Below the 'true' is included to prevent unnecessarily many errors.
@if [ -n "${LATEXTARGET}" ]; then \
$(MAKE) ${LATEXTARGET}.dvi; \
true; \
else \
if [ `ls *.tex | wc -l` = "1" ]; then \
$(MAKE) `basename \`ls *.tex\` .tex`.dvi; \
true; \
else \
$(MAKE) `echo $$PWD|tr '/' '\n'|tail -1`.dvi; \
true; \
fi; \
fi
latexfigures: latexfigures:
@for i in $(FIGUREOBJS); do \ @for i in $(FIGUREOBJS); do \
$(MAKE) $$i; \ $(MAKE) $$i; \
done done
view: viewdvi:
# Below the 'true' is included to prevent unnecessarily many errors. # Below the 'true' is included to prevent unnecessarily many errors.
@if [ -n "${LATEXTARGET}" ]; then \ @if [ -n "${LATEXTARGET}" ]; then \
$(MAKE) ${LATEXTARGET}.dvi && \ $(MAKE) ${LATEXTARGET}.dvi && \
@ -324,6 +328,24 @@ view:
fi; \ fi; \
fi fi
view:
# Below the 'true' is included to prevent unnecessarily many errors.
@if [ -n "${LATEXTARGET}" ]; then \
$(MAKE) ${LATEXTARGET}.pdf && \
$(PDFVIEWER) ${LATEXTARGET}.pdf; \
true; \
else \
if [ `ls *.tex | wc -l` = "1" ]; then \
$(MAKE) `basename \`ls *.tex\` .tex`.pdf && \
$(PDFVIEWER) `basename \`ls *.tex\` .tex`.pdf; \
true; \
else \
$(MAKE) `echo $$PWD|tr '/' '\n'|tail -1`.pdf && \
$(PDFVIEWER) `echo $$PWD|tr '/' '\n'|tail -1`.pdf; \
true; \
fi; \
fi
%.ps: %.dvi %.ps: %.dvi
$(DVIPS) -o $@ $< $(DVIPS) -o $@ $<

View File

@ -1,3 +1,4 @@
% $Id$
\chapter{Beispiele} \chapter{Beispiele}
@ -12,67 +13,132 @@ Angenommen, bei der Benutzung eines Rechners tritt ein Problem auf, bei dem nur
Einfacher geht es, wenn wir uns ein kurzes Skript schreiben, das alle 30 Sekunden automatisch überprüft, ob der Admin angemeldet ist. Wir erreichen das mit dem folgenden Code: Einfacher geht es, wenn wir uns ein kurzes Skript schreiben, das alle 30 Sekunden automatisch überprüft, ob der Admin angemeldet ist. Wir erreichen das mit dem folgenden Code:
\footnotesize
\index{\^=\texttt{\^}}\index{Anführungszeichen}\index{Pipe}\index{grep=\texttt{grep}}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}} \index{\^=\texttt{\^}}\index{Anführungszeichen}\index{Pipe}\index{grep=\texttt{grep}}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}}
\begin{listing}[2]{1} \begin{lstlisting}
#!/bin/sh #!/bin/sh
until who | grep "^root " until who | grep "^root "; do
do sleep 30 sleep 30
done done
echo Big Brother is watching you! echo "Big Brother is watching you!"
\end{listing} \end{lstlisting}
\normalsize
Das Skript führt also so lange das Kommando aus, bis die Ausführung erfolgreich war. Dabei wird die Ausgabe von \texttt{who}\index{who=\texttt{who}} mit einer Pipe (\ref{datenstrom}) in das \texttt{grep}\index{grep=\texttt{grep}}-Kommando umgeleitet. Dieses sucht darin nach einem Auftreten von `\texttt{root~}' am Zeilenanfang. Der Rückgabewert von \texttt{grep}\index{grep=\texttt{grep}} ist 0 wenn das Muster\index{Mustererkennung} gefunden wird, 1 wenn es nicht gefunden wird und 2 wenn ein Fehler auftrat. Damit der Rechner nicht die ganze Zeit mit dieser Schleife beschäftigt ist, wird im Schleifenkörper ein \texttt{sleep 30}\index{sleep=\texttt{sleep}} ausgeführt, um den Prozeß für 30 Sekunden schlafen zu schicken. Sobald der Admin sich eingeloggt hat, wird eine entsprechende Meldung ausgegeben. Das Skript führt also so lange das Kommando aus, bis die Ausführung erfolgreich
war. Dabei wird die Ausgabe von \texttt{who}\index{who=\texttt{who}} mit einer
Pipe (\ref{datenstrom}) in das \texttt{grep}\index{grep=\texttt{grep}}-Kommando
umgeleitet. Dieses sucht darin nach einem Auftreten von `\texttt{root~}' am
Zeilenanfang. Der Rückgabewert von \texttt{grep}\index{grep=\texttt{grep}} ist
0 wenn das Muster\index{Mustererkennung} gefunden wird, 1 wenn es nicht
gefunden wird und 2 wenn ein Fehler auftrat. Damit der Rechner nicht die ganze
Zeit mit dieser Schleife beschäftigt ist, wird im Schleifenkörper ein
\lstinline|sleep 30|\index{sleep=\texttt{sleep}} ausgeführt, um den Prozeß für
30 Sekunden schlafen zu schicken. Sobald der Admin sich eingeloggt hat, wird
eine entsprechende Meldung ausgegeben.
\subsection{Schleife, bis ein Kommando erfolglos war} \subsection{Schleife, bis ein Kommando erfolglos war}
Analog zum vorhergehenden Beispiel kann man auch ein Skript schreiben, das meldet, sobald sich ein Benutzer abgemeldet hat. Dazu ersetzen wir nur die \texttt{until}- Schleife durch eine entsprechende \texttt{while}-Schleife: Analog zum vorhergehenden Beispiel kann man auch ein Skript schreiben, das
meldet, sobald sich ein Benutzer abgemeldet hat. Dazu ersetzen wir nur die
\texttt{until}- Schleife durch eine entsprechende \texttt{while}-Schleife:
\footnotesize
\index{\^=\texttt{\^}}\index{Anführungszeichen}\index{grep=\texttt{grep}}\index{Pipe}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}} \index{\^=\texttt{\^}}\index{Anführungszeichen}\index{grep=\texttt{grep}}\index{Pipe}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}}
\begin{listing}[2]{1} \begin{lstlisting}
#!/bin/sh #!/bin/sh
while who | grep "^root " while who | grep "^root "; do
do sleep 30 sleep 30
done 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{listing} \end{lstlisting}
\normalsize
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. 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.
\section{Eine Datei zeilenweise bearbeiten} \section{Subshell-Schleifen vermeiden}\label{subshellschleifen}
\texttt{cat datei.txt | while read i} Wir wollen ein Skript schreiben, das die \texttt{/etc/passwd} liest und dabei
zählt, wie viele Benutzer eine UID kleiner als 100 haben.
TODO!!! Folgendes Skript funktioniert nicht:
\begin{lstlisting}
#!/bin/sh
count=0
cat /etc/passwd | while read i; do
uid=`echo $i | cut -f 3 -d:`
if [ $uid -lt 100 ]; then
count=`expr $count + 1`
echo $count
fi
done
echo Es sind $count Benutzer mit einer ID kleiner 100 eingetragen
\end{lstlisting}
Was ist passiert?
Dieses Skript besteht im Wesentlichen aus einer Pipe. Wir haben ein
\texttt{cat}-Kom\-man\-do, das den Inhalt der \texttt{/etc/passwd} durch eben
diese Pipe an eine Schleife übergibt. Das \texttt{read}-Kommando in der
Schleife liest die einzelnen Zeilen aus, dann folgt ein Bißchen Auswertung.
Es ist zu beobachten, daß bei der Ausgabe in Zeile 7 die Variable
\texttt{\$count} korrekte Werte enthält. Um so unverständlicher ist es, daß sie
nach der Vollendung der Schleife wieder den Wert 0 enthält.
Das liegt daran, daß diese Schleife als Teil einer Pipe in einer Subshell
ausgeführt wird. Die Variable \texttt{\$count} steht damit in der Schleife
praktisch nur lokal zur Verfügung, sie wird nicht an das umgebende Skript
`hochgereicht'.
Neben der Methode in \ref{daten_hochreichen} bietet sich hier eine viel
einfachere Lösung an:
\begin{lstlisting}
#!/bin/sh
count=0
while read i; do
uid=`echo $i | cut -f 3 -d:`
if [ $uid -lt 100 ]; then
count=`expr $count + 1`
echo $count
fi
done < /etc/passwd
echo Es sind $count Benutzer mit einer ID kleiner 100 eingetragen
\end{lstlisting}
Hier befindet sich die Schleife nicht in einer Pipe, daher wird sie auch nicht
in einer Subshell ausgeführt. Man kann auf das \texttt{cat}-Kommando verzichten
und den Inhalt der Datei durch die Umlenkung in Zeile 9 direkt auf die
Standardeingabe der Schleife (und somit auf das \texttt{read}-Kommando) legen.
Achtung! while ist eine Subshell - Daten müssen hochgereicht werden.
\section{Ein typisches Init-Skript}\label{init-skript}\index{Init-Skript} \section{Ein typisches Init-Skript}\label{init-skript}\index{Init-Skript}
Dieses Skript dient dazu, den Apache HTTP-Server zu starten. Es wird während des Bootvorgangs gestartet, wenn der dazugehörige Runlevel initialisiert wird. Dieses Skript dient dazu, den Apache HTTP-Server zu starten. Es wird während
des Bootvorgangs gestartet, wenn der dazugehörige Runlevel initialisiert wird.
Das Skript muß mit einem Parameter\index{Parameter} aufgerufen werden. Möglich sind hier \textsl{start}, \textsl{stop}, \textsl{status}, \textsl{restart} und \textsl{reload}. Wenn falsche Parameter\index{Parameter} übergeben wurden, wird eine entsprechende Meldung angezeigt. Das Skript muß mit einem Parameter\index{Parameter} aufgerufen werden. Möglich
sind hier \textsl{start}, \textsl{stop}, \textsl{status}, \textsl{restart} und
\textsl{reload}. Wenn falsche Parameter\index{Parameter} übergeben wurden, wird
eine entsprechende Meldung angezeigt.
Das Ergebnis der Ausführung wird mit Funktionen\index{Funktion} dargestellt, die aus der Datei \texttt{/etc/rc.d/init.d/functions} stammen. Ebenfalls in dieser Datei sind Funktionen, die einen Dienst starten oder stoppen. Das Ergebnis der Ausführung wird mit Funktionen\index{Funktion} dargestellt,
die aus der Datei \lstinline|functions| stammen. Ebenfalls in dieser Datei sind
Funktionen, die einen Dienst starten oder stoppen.
\begin{flushright} Zunächst wird festgelegt, daß dieses Skript in der Bourne-Shell ausgeführt
Zunächst wird festgelegt, daß dieses Skript in der Bourne-Shell ausgeführt werden soll (\ref{auswahl_der_shell}). werden soll (\ref{auswahl_der_shell}).
\end{flushright}
\footnotesize \begin{lstlisting}
\begin{listing}[2]{1}
#!/bin/sh #!/bin/sh
\end{listing}
\normalsize \end{lstlisting}
\begin{flushright}
Dann folgen Kommentare\index{Kommentar}, die den Sinn des Skriptes erläutern (\ref{kommentare}). Dann folgen Kommentare\index{Kommentar}, die den Sinn des Skriptes erläutern
\end{flushright} (\ref{kommentare}).
\footnotesize
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
# #
# Startup script for the Apache Web Server # Startup script for the Apache Web Server
# #
@ -84,119 +150,109 @@ Dann folgen Kommentare\index{Kommentar}, die den Sinn des Skriptes erl
# config: /etc/httpd/conf/access.conf # config: /etc/httpd/conf/access.conf
# config: /etc/httpd/conf/httpd.conf # config: /etc/httpd/conf/httpd.conf
# config: /etc/httpd/conf/srm.conf # config: /etc/httpd/conf/srm.conf
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Jetzt wird die Datei mit den Funktionen\index{Funktion} eingebunden (\ref{source}). Jetzt wird die Datei mit den Funktionen\index{Funktion} eingebunden (\ref{source}).
\end{flushright}
\footnotesize
\index{source=\texttt{source}} \index{source=\texttt{source}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
# Source function library. # Source function library.
. /etc/rc.d/init.d/functions . /etc/rc.d/init.d/functions
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Hier werden die Aufrufparameter ausgewertet (\ref{case}). Hier werden die Aufrufparameter ausgewertet (\ref{case}).
\end{flushright}
\footnotesize
\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{case=\texttt{case}} \index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{case=\texttt{case}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
# See how we were called. # See how we were called.
case "$1" in case "$1" in
start) start)
echo -n "Starting httpd: " echo -n "Starting httpd: "
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Nachdem eine Meldung über den auszuführenden Vorgang ausgegeben wurde, wird die Funktion \texttt{daemon} aus der Funktionsbibliothek ausgeführt. Diese Funktion startet das Programm, dessen Name hier als Parameter\index{Parameter} übergeben wird. Dann gibt sie eine Meldung über den Erfolg aus. Nachdem eine Meldung über den auszuführenden Vorgang ausgegeben wurde, wird die Funktion \texttt{daemon} aus der Funktionsbibliothek ausgeführt. Diese Funktion startet das Programm, dessen Name hier als Parameter\index{Parameter} übergeben wird. Dann gibt sie eine Meldung über den Erfolg aus.
\end{flushright}
\footnotesize \begin{lstlisting}[firstnumber=last]
\begin{listingcont}
daemon httpd daemon httpd
echo echo
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Jetzt wird ein Lock-File\footnote{Ein Lock-File signalisiert anderen Prozessen, daß ein bestimmter Prozeß bereits gestartet ist. So kann ein zweiter Aufruf verhindert werden.} angelegt. Jetzt wird ein Lock-File\footnote{Ein Lock-File signalisiert anderen Prozessen, daß ein bestimmter Prozeß bereits gestartet ist. So kann ein zweiter Aufruf verhindert werden.} angelegt.
\end{flushright}
\footnotesize
\index{Anführungszeichen}\index{touch=\texttt{touch}} \index{Anführungszeichen}\index{touch=\texttt{touch}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
touch /var/lock/subsys/httpd touch /var/lock/subsys/httpd
;; ;;
stop) stop)
echo -n "Shutting down http: " echo -n "Shutting down http: "
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Hier passiert im Prinzip das gleiche wie oben, nur daß mit der Funktion \texttt{killproc} der Daemon angehalten wird. Hier passiert im Prinzip das gleiche wie oben, nur daß mit der Funktion \texttt{killproc} der Daemon angehalten wird.
\end{flushright}
\footnotesize \begin{lstlisting}[firstnumber=last]
\begin{listingcont}
killproc httpd killproc httpd
echo echo
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Danach werden Lock-File und PID-File\footnote{In einem sogenannten PID-File hinterlegen einige Prozesse ihre Prozeß-ID, um anderen Programmen den Zugriff zu erleichtern (z. B. um den Prozeß anzuhalten etc).} gelöscht. Danach werden Lock-File und PID-File\footnote{In einem sogenannten PID-File hinterlegen einige Prozesse ihre Prozeß-ID, um anderen Programmen den Zugriff zu erleichtern (z. B. um den Prozeß anzuhalten etc).} gelöscht.
\end{flushright}
\footnotesize \begin{lstlisting}[firstnumber=last]
\begin{listingcont}
rm -f /var/lock/subsys/httpd rm -f /var/lock/subsys/httpd
rm -f /var/run/httpd.pid rm -f /var/run/httpd.pid
;; ;;
status) status)
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Die Funktion \texttt{status} stellt fest, ob der entsprechende Daemon bereits läuft, und gibt das Ergebnis aus. Die Funktion \texttt{status} stellt fest, ob der entsprechende Daemon bereits läuft, und gibt das Ergebnis aus.
\end{flushright}
\footnotesize \begin{lstlisting}[firstnumber=last]
\begin{listingcont}
status httpd status httpd
;; ;;
restart) restart)
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Bei Aufruf mit dem Parameter\index{Parameter} \textsl{restart} ruft sich das Skript zwei mal selbst auf (in \texttt{\$0} steht der Aufrufname des laufenden Programms). Einmal, um den Daemon zu stoppen, dann, um ihn wieder zu starten. Bei Aufruf mit dem Parameter\index{Parameter} \textsl{restart} ruft sich das Skript zwei mal selbst auf (in \texttt{\$0} steht der Aufrufname des laufenden Programms). Einmal, um den Daemon zu stoppen, dann, um ihn wieder zu starten.
\end{flushright}
\footnotesize
\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen} \index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
$0 stop $0 stop
$0 start $0 start
;; ;;
reload) reload)
echo -n "Reloading httpd: " echo -n "Reloading httpd: "
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Hier sendet die \texttt{killproc}-Funktion dem Daemon ein Signal\index{Signal} das ihm sagt, daß er seine Konfiguration neu einlesen soll. Hier sendet die \texttt{killproc}-Funktion dem Daemon ein Signal\index{Signal} das ihm sagt, daß er seine Konfiguration neu einlesen soll.
\end{flushright}
\footnotesize
\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen} \index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
killproc httpd -HUP killproc httpd -HUP
echo echo
;; ;;
*) *)
echo "Usage: $0 {start|stop|restart|reload|status}" echo "Usage: $0 {start|stop|restart|reload|status}"
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Bei aufruf mit einem beliebigen anderen Parameter\index{Parameter} wird eine Kurzhilfe ausgegeben. Dann wird dafür gesorgt, daß das Skript mit dem Exit-Code 1 beendet wird. So kann festgestellt werden, ob das Skript ordnungsgemäß beendet wurde (\ref{exit}). Bei aufruf mit einem beliebigen anderen Parameter\index{Parameter} wird eine Kurzhilfe ausgegeben. Dann wird dafür gesorgt, daß das Skript mit dem Exit-Code 1 beendet wird. So kann festgestellt werden, ob das Skript ordnungsgemäß beendet wurde (\ref{exit}).
\end{flushright}
\footnotesize
\index{exit=\texttt{exit}} \index{exit=\texttt{exit}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
exit 1 exit 1
esac esac
exit 0 exit 0
\end{listingcont}
\normalsize \end{lstlisting}
\section{Parameterübergabe in der Praxis}\label{beisp_parameter}\index{Parameter} \section{Parameterübergabe in der Praxis}\label{beisp_parameter}\index{Parameter}
@ -205,21 +261,19 @@ Es kommt in der Praxis sehr oft vor, da
Das soll an folgendem Skript verdeutlicht werden. Das Skript kennt die Optionen \texttt{-a} und \texttt{-b}. Letzterer Option muß ein zusätzlicher Wert mitgegeben werden. Alle anderen Parameter\index{Parameter} werden als Dateinamen interpretiert. Das soll an folgendem Skript verdeutlicht werden. Das Skript kennt die Optionen \texttt{-a} und \texttt{-b}. Letzterer Option muß ein zusätzlicher Wert mitgegeben werden. Alle anderen Parameter\index{Parameter} werden als Dateinamen interpretiert.
\footnotesize
\index{\$@=\texttt{\$@}}\index{Anführungszeichen}\index{Backticks}\index{!|!|=\texttt{!|!|}}\index{getopt=\texttt{getopt}}\index{OR}\index{set=\texttt{set}} \index{\$@=\texttt{\$@}}\index{Anführungszeichen}\index{Backticks}\index{!|!|=\texttt{!|!|}}\index{getopt=\texttt{getopt}}\index{OR}\index{set=\texttt{set}}
\begin{listing}[2]{1} \begin{lstlisting}
#!/bin/sh #!/bin/sh
set -- `getopt "ab:" "$@"` || { set -- `getopt "ab:" "$@"` || {
\end{listing}
\normalsize \end{lstlisting}
\begin{flushright}
Das \texttt{set}\index{set=\texttt{set}}-Kommando belegt den Inhalt der vordefinierten Variablen (\ref{vordefinierte_variablen}) neu, so daß es aussieht, als ob dem Skript die Rückgabewerte von \texttt{getopt}\index{getopt=\texttt{getopt}} übergeben wurden. Man muß die beiden Minuszeichen angeben, da sie dafür sorgen, daß die Aufrufparameter an \texttt{getopt}\index{getopt=\texttt{getopt}} und nicht an die Shell selbst übergeben werden. Die originalen Parameter\index{Parameter} werden von \texttt{getopt}\index{getopt=\texttt{getopt}} untersucht und modifiziert zurückgegeben: \texttt{a} und \texttt{b} werden als Parameter\index{Parameter} Markiert, \texttt{b} sogar mit der Möglichkeit einer zusätzlichen Angabe. Das \texttt{set}\index{set=\texttt{set}}-Kommando belegt den Inhalt der vordefinierten Variablen (\ref{vordefinierte_variablen}) neu, so daß es aussieht, als ob dem Skript die Rückgabewerte von \texttt{getopt}\index{getopt=\texttt{getopt}} übergeben wurden. Man muß die beiden Minuszeichen angeben, da sie dafür sorgen, daß die Aufrufparameter an \texttt{getopt}\index{getopt=\texttt{getopt}} und nicht an die Shell selbst übergeben werden. Die originalen Parameter\index{Parameter} werden von \texttt{getopt}\index{getopt=\texttt{getopt}} untersucht und modifiziert zurückgegeben: \texttt{a} und \texttt{b} werden als Parameter\index{Parameter} Markiert, \texttt{b} sogar mit der Möglichkeit einer zusätzlichen Angabe.
Wenn dieses Kommando fehlschlägt ist das ein Zeichen dafür, daß falsche Parameter\index{Parameter} übergeben wurden. Also wird nach einer entsprechenden Meldung das Programm mit Exit-Code 1 verlassen. Wenn dieses Kommando fehlschlägt ist das ein Zeichen dafür, daß falsche Parameter\index{Parameter} übergeben wurden. Also wird nach einer entsprechenden Meldung das Programm mit Exit-Code 1 verlassen.
\end{flushright}
\footnotesize
\index{\$n=\texttt{\$}$n$}\index{Null-Befehl}\index{!>\&=\texttt{!>\&}}\index{!==\texttt{!=}}\index{Anführungszeichen}\index{Backticks}\index{basename=\texttt{basename}} \index{\$n=\texttt{\$}$n$}\index{Null-Befehl}\index{!>\&=\texttt{!>\&}}\index{!==\texttt{!=}}\index{Anführungszeichen}\index{Backticks}\index{basename=\texttt{basename}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
echo "Anwendung: `basename $0` [-a] [-b Name] Dateien" 1>&2 echo "Anwendung: `basename $0` [-a] [-b Name] Dateien" 1>&2
exit 1 exit 1
} }
@ -227,98 +281,284 @@ echo "Momentan steht in der Kommandozeile folgendes: $*"
aflag=0 name=NONE aflag=0 name=NONE
while : while :
do do
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
In einer Endlosschleife\index{Endlosschleife}, die man mit Hilfe des Null-Befehls (\texttt{:}, \ref{null-befehl}) baut, werden die `neuen' Parameter\index{Parameter} der Reihe nach untersucht. Wenn ein \texttt{-a} vorkommt, wird die Variable \texttt{aflag} gesetzt. Bei einem \texttt{-b} werden per \texttt{shift}\index{shift=\texttt{shift}} alle Parameter\index{Parameter} nach Links verschoben, dann wird der Inhalt des nächsten Parameters\index{Parameter} in der Variablen \texttt{name} gesichert. In einer Endlosschleife\index{Endlosschleife}, die man mit Hilfe des Null-Befehls (\texttt{:}, \ref{null-befehl}) baut, werden die `neuen' Parameter\index{Parameter} der Reihe nach untersucht. Wenn ein \texttt{-a} vorkommt, wird die Variable \texttt{aflag} gesetzt. Bei einem \texttt{-b} werden per \texttt{shift}\index{shift=\texttt{shift}} alle Parameter\index{Parameter} nach Links verschoben, dann wird der Inhalt des nächsten Parameters\index{Parameter} in der Variablen \texttt{name} gesichert.
\end{flushright}
\footnotesize
\index{!==\texttt{!=}}\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{case=\texttt{case}}\index{shift=\texttt{shift}} \index{!==\texttt{!=}}\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{case=\texttt{case}}\index{shift=\texttt{shift}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
case "$1" in case "$1" in
-a) aflag=1 ;; -a) aflag=1 ;;
-b) shift; name="$1" ;; -b) shift; name="$1" ;;
--) break ;; --) break ;;
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Wenn ein \texttt{-{}-} erscheint, ist das ein Hinweis darauf, daß die Liste der Parameter\index{Parameter} abgearbeitet ist. Dann wird per \texttt{break}\index{break=\texttt{break}} (\ref{break}) die Endlosschleife unterbrochen. Die Aufrufparameter enthalten jetzt nur noch die eventuell angegebenen Dateinamen, die jetzt von dem Restlichen Skript wie gewohnt weiterverarbeitet werden können. Wenn ein \texttt{-{}-} erscheint, ist das ein Hinweis darauf, daß die Liste der Parameter\index{Parameter} abgearbeitet ist. Dann wird per \texttt{break}\index{break=\texttt{break}} (\ref{break}) die Endlosschleife unterbrochen. Die Aufrufparameter enthalten jetzt nur noch die eventuell angegebenen Dateinamen, die jetzt von dem Restlichen Skript wie gewohnt weiterverarbeitet werden können.
\end{flushright}
\footnotesize
\index{shift=\texttt{shift}} \index{shift=\texttt{shift}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
esac esac
shift shift
done done
shift shift
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
Am Ende werden die Feststellungen ausgegeben. Am Ende werden die Feststellungen ausgegeben.
\end{flushright}
\footnotesize
\index{\$*=\texttt{\$*}}\index{Anführungszeichen} \index{\$*=\texttt{\$*}}\index{Anführungszeichen}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
echo "aflag=$aflag / Name = $name / Die Dateien sind $*" echo "aflag=$aflag / Name = $name / Die Dateien sind $*"
\end{listingcont}
\normalsize \end{lstlisting}
\section{Fallensteller: Auf Traps \section{Fallensteller: Auf Traps reagieren}\label{traps}\index{trap=\texttt{trap}|(}\index{Signal|(}
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
(\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} \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.
\footnotesize
\index{!==\texttt{!=}} \index{!==\texttt{!=}}
\begin{listing}[2]{1} \begin{lstlisting}
#!/bin/sh #!/bin/sh
stat=1 stat=1
temp=/tmp/zeige$$ temp=/tmp/zeige$$
\end{listing}
\normalsize \end{lstlisting}
\begin{flushright}
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
\end{flushright} sollen. In \texttt{stat} wird der Wert abgelegt, den das Skript im Falle eines
\footnotesize 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}} \index{Ticks}\index{!>\&=\texttt{!>\&}}\index{\$n=\texttt{\$}$n$}\index{Ticks}\index{Anführungszeichen}\index{Backticks}\index{basename=\texttt{basename}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
trap 'rm -f $temp; exit $stat' 0 trap 'rm -f $temp; exit $stat' 0
trap 'echo "`basename $0`: Ooops..." 1>&2' 1 2 15 trap 'echo "`basename $0`: Ooops..." 1>&2' 1 2 15
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
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
\end{flushright} und der Wert aus der Variable \texttt{stat} als Exit-Code zurückgegeben. Dabei
\footnotesize 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}} \index{\$\#=\texttt{\$\#}}\index{!==\texttt{!=}}\index{!>=\texttt{!>}}\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{case=\texttt{case}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
case $# in case $# in
1) zcat "$1" > $temp 1) zcat "$1" > $temp
pg $temp pg $temp
stat=0 stat=0
;; ;;
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
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
\end{flushright} \texttt{case}-Kommando (\ref{case}) testet die Anzahl der übergebenen
\footnotesize 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}} \index{!>\&=\texttt{!>\&}}\index{\$n=\texttt{\$}$n$}\index{Anführungszeichen}\index{Backticks}\index{basename=\texttt{basename}}
\begin{listingcont} \begin{lstlisting}[firstnumber=last]
*) echo "Anwendung: `basename $0` Dateiname" 1>&2 *) echo "Anwendung: `basename $0` Dateiname" 1>&2
esac esac
\end{listingcont}
\normalsize \end{lstlisting}
\begin{flushright}
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
\end{flushright} der Aufrufsyntax auf die Standard-Fehlerausgabe geschrieben.
\index{trap=\texttt{trap}|)}\index{Signal|)} \index{trap=\texttt{trap}|)}\index{Signal|)}
\section{Chaoten: Dateien in zufällige Reihenfolge bringen}\label{chaoten}\index{Zufallszahlen|(}
Wir wollen uns einen MP3-Player programmieren, der Alle MP3-Dateien aus einem
bestimmten Verzeichnisbaum in zufälliger Reihenfolge abspielt. Damit dieses
Problem für uns eine Herausforderung darstellt\footnote{Denn schließlich hat
mpg123 schon von Hause aus eine Random-Funktion.}, wollen wir vor dem Abspielen
der jeweiligen Datei etwas mit dem Dateinamen anstellen. Ob das eine einfache
Ausgabe per \texttt{echo} ist, oder ob der Name per Sprachsynthese oder auf
einem externen Display angezeigt werden soll ist an dieser Stelle egal.
Das Problem ist, daß wir in der Shell nur über Umwege an Zufallszahlen kommen
können. Auf Systemen, in denen die Datei \texttt{/dev/urandom} existiert,
liefert uns der Kernel aber schon sehr zufällige Zeichenfolgen. Diese Folgen
können alle Zeichen enthalten, daher müssen sie vor der Benutzung für unsere
Zwecke noch etwas `bereinigt' werden.
Wie das aussieht, wenn es fertig ist, sieht man im folgenden Skript:
\index{!==\texttt{!=}}
\begin{lstlisting}
#!/bin/sh
for i in `find $1 -type f -name "*.[mM][pP]3"`; do
\end{lstlisting}
Hier beginnt eine Schleife, die über alle Ausgaben des \texttt{find}-Kommandos
iteriert. Dabei sucht \texttt{find} nach allen normalen Dateien (\texttt{-type
f}), die die Extension .mp3 tragen (\texttt{-name \dq*.[mM][pP]3\dq} -- wir
ignorieren Groß- / Kleinschreibung).
\index{find=\texttt{find}}
\begin{lstlisting}[firstnumber=last]
echo `tr -dc "[:alpha:]" < /dev/urandom | \
dd count=8 bs=1 2> /dev/null`$i
\end{lstlisting}
Hier ist der `magische Teil'. Mit dem \texttt{echo} wird die Ausgabe einer Pipe
ausgegeben, gefolgt von dem aktuellen Dateinamen. Diese Pipe enthält ein
\texttt{tr}, der alle ungewollten Zeichen (alles, was kein Textzeichen ist) aus
einem Datenstrom entfernt. Die Daten erhält \texttt{tr} durch die
\texttt{<}-Umleitung aus oben genannter Datei.
Diese Datei liefert `ohne Ende' Zeichen. Wir wollen aber nur acht Zeichen
haben, die wir unserem Dateinamen voranstellen können. Dazu benutzen wir das
Kommando \texttt{dd} mit den angegebenen Parametern. Damit die Erfolgsmeldung
von \texttt{dd} nicht die Ausgabe verunstaltet, lenken wir sie nach
\texttt{/dev/null} um.
\index{tr=\texttt{tr}}\index{dd=\texttt{dd}}
\index{find=\texttt{find}}
\begin{lstlisting}[firstnumber=last]
done | sort | cut -b 9- | while read i; do
\end{lstlisting}
Das Ergebnis der obigen Schleife ist also die Liste der Dateinamen, denen
jeweils acht zufällige Zeichen vorangestellt wurden. Die Reihenfolge entspricht
allerdings immer noch der Ausgabe von \texttt{find}, wird also nach jedem
Durchlauf gleich sein.
Um das zu ändern, pipen wir die Ausgabe der Schleife durch ein \texttt{sort}.
Da die ersten acht Zeichen jeder Zeile zufällig sind, erhalten wir so eine
zufällige Reihenfolge der Zeilen. Jetzt müssen wir nur noch durch ein
\texttt{cut} die zufälligen Zeichen abschneiden, und erhalten so die
ursprüngliche Liste von Dateien in einer zufälligen Reihenfolge.
Diese lesen wir jetzt zeilenweise mittels \texttt{read} ein. In der
\texttt{while}-Schleife können wir alle erforderlichen Sachen mit dem
Dateinamen anstellen. Hier wird er nur mittels \texttt{echo} ausgegeben.
\index{sort=\texttt{sort}}\index{cut=\texttt{cut}} \index{read=\texttt{read}}\index{while=\texttt{while}}
\index{find=\texttt{find}}
\begin{lstlisting}[firstnumber=last]
echo "Jetzt wird $i gespielt"
mpg123 "$i"
done
\end{lstlisting}
\index{Zufallszahlen|)}
\section{Wer suchet, der findet}\label{beispiele_suchen}\index{grep=\texttt{grep}|(textbf}
\subsection{Prozesse suchen}\label{beispiele_suchen_prozesse}\index{ps=\texttt{ps}|(textbf}\index{pgrep=\texttt{pgrep}|(textbf}
Im Zusammenhang mit grep stößt fast jeder Shell-Skripter früher oder später auf
das Problem, daß er irgendwas davon abhängig machen will, ob ein bestimmter
Prozeß läuft oder nicht. Im Normalfall wird er zuerst folgendes ausprobieren,
was aber oft (nicht immer) in die Hose gehen wird:
\lstinline/ps aux | grep prozessname && echo "läuft schon"/
Der Grund dafür ist, daß unter Umständen in der Ausgabe von \texttt{ps} auch
das \texttt{grep}-Kommando samt Parameter (\textit{prozessname}) aufgelistet
wird. So findet das \texttt{grep}-Kom\-man\-do sich quasi selbst.
Abhilfe schafft entweder \texttt{pgrep} (\ref{pgrep}) oder das folgende
Konstrukt:
\lstinline/ps aux | grep "[p]rozessname" && echo "läuft schon"/
Das p ist jetzt als eine Zeichenmenge (regulärer Ausdruck) angegeben worden.
Jetzt sucht \texttt{grep} also nach dem String \textit{prozessname}, in der
Ausgabe von \texttt{ps} erscheint das \texttt{grep}-Kommando allerdings mit
\textit{[p]rozessname} und wird somit ignoriert.
\index{ps=\texttt{ps}|)textbf}\index{pgrep=\texttt{pgrep}|)textbf}
\subsection{Dateiinhalte suchen}\label{beispiele_suchen_dateien}\index{find=\texttt{find}|(textbf}
Ein weiterer wertvoller Trick, diesmal im Zusammenhang mit \texttt{find}, ist
folgendes Szenario: Es gibt ein Verzeichnis mit vielen Unterverzeichnissen,
überall liegen Perl-Skripte und andere Dateien. Gesucht sind alle Dateien, in
denen eine Zeile mit dem Inhalt `strict' vorkommt. Man könnte jetzt
folgendes versuchen:
\lstinline|grep -r strict *|
Das führt allerdings dazu, daß alle Dateien durchsucht werden, nicht nur die
Perl-Skripte. Diese tragen nach unserer Konvention\footnote{Perl-Skripte müssen
keine spezielle Extension haben, es sei aber um des Beispiels Willen mal
angenommen.} die Extension `.pl'. Wir starten also eine rekursive Suche über
alle Dateien, die dem Muster entsprechen:
\lstinline|grep -r strict *.pl|
Und wieder führt es nicht zu dem gewünschten Ergebnis. Da die
Unterverzeichnisse nicht die Extension `*.pl' tragen, werden sie nicht
berücksichtigt. Für die Suche in Unterverzeichnissen ziehen wir \texttt{find}
(Siehe Abschnitt \ref{find}) heran:
\lstinline|find . -name \*.pl -exec grep strict {} \;|
Dieser Befehl gibt uns zwar die gefundenen Zeilen aus, nicht aber die Namen der
Dateien. Es sieht für \texttt{grep} so aus als ob nur eine Datei durchsucht
würde, da besteht keine Notwendigkeit den Namen anzugeben. Das ginge mit dem
Parameter \texttt{-l}, allerdings würden uns dann nur noch die Dateinamen
angezeigt. Eine Ausgabe mit beiden Informationen erhalten wir mit dem folgenden
Konstrukt:
\lstinline|find . -name \*.pl -exec grep strict /dev/null {} \;|
Hier durchsucht \texttt{grep} nicht nur die gefundenen Dateien, sondern bei
jedem Aufruf auch \texttt{/dev/null}, also den digitalen Mülleimer der per
Definition leer ist. Da es für \texttt{grep} so aussieht als ob mehr als eine
Datei durchsucht würden, wird bei jeder Fundstelle sowohl der Dateiname als
auch die gefundene Zeile ausgegeben.
\index{find=\texttt{find}|)textbf}
\index{grep=\texttt{grep}|)textbf}

View File

@ -1,10 +1,17 @@
\chapter{Quellen} % $Id$
\chapter{Quellen}\label{quellen}
\begin{itemize} \begin{itemize}
\item Bash Reference Manual (\texttt{http://www.gnu.org/manual/bash-2.02/\\bashref.html}) \item Bash Reference Manual (\href{http://www.gnu.org/software/bash/manual/bashref.html}{http://www.gnu.org/software/bash/manual/bashref.html})
\item Unix In A Nutshell (\texttt{http://www.oreilly.com/catalog/unixnut3/}) \item Die Man-Page der Bash
\item Unix Power Tools (\texttt{http://www.oreilly.com/catalog/upt2/}) \item Die deutschsprachige Shell-Newsgroup (\href{news://de.comp.os.unix.shell}{news://de.comp.os.unix.shell})
\item Von DOS nach Linux HOWTO (\texttt{http://www.tu-harburg.de/\\\~{}semb2204/dlhp/HOWTO/DE-DOS-nach-Linux-HOWTO.html}) \item Unix In A Nutshell (\href{http://www.oreilly.com/catalog/unixnut3/}{http://www.oreilly.com/catalog/unixnut3/})
\item Unix Power Tools (\href{http://www.oreilly.com/catalog/upt2/}{http://www.oreilly.com/catalog/upt2/})
\item Von DOS nach Linux HOWTO (\href{http://www.linuxhaven.de/dlhp/HOWTO/DE-DOS-nach-Linux-HOWTO.html}{http://www.linuxhaven.de/dlhp/HOWTO/DE-DOS-nach-Linux-HOWTO.html})
\item Bash Guide for Beginners (\href{http://tldp.org/LDP/Bash-Beginners-Guide/}{http://tldp.org/LDP/Bash-Beginners-Guide/})
\item Advanced Bash-Scripting Guide (\href{http://tldp.org/LDP/abs/}{http://tldp.org/LDP/abs/})
\item The Open Group Base Specifications
\item Single Unix Specifications V2
\item ... und eine Menge Skripte, die ich im Laufe der Zeit gelesen habe (das \item ... und eine Menge Skripte, die ich im Laufe der Zeit gelesen habe (das
kann ich nur jedem empfehlen - es ist spannender als es sich anhört...). kann ich nur jedem empfehlen - es ist spannender als es sich anhört...).
\end{itemize} \end{itemize}

View File

@ -1,3 +1,4 @@
% $Id$
\chapter{Schmutzige Tricks :-)} \chapter{Schmutzige Tricks :-)}
Eigentlich sind diese Tricks gar nicht so schmutzig. Hier ist lediglich eine Eigentlich sind diese Tricks gar nicht so schmutzig. Hier ist lediglich eine
@ -23,29 +24,411 @@ haben.
\section{Die Tar-Brücke} \section{Die Tar-Brücke}
TODO!!! Eine sogenannte Tar-Brücke benutzt man, wenn eine oder mehrere Dateien zwischen
Rechnern übertragen werden sollen, aber kein Dienst wie SCP oder FTP zur
Verfügung steht. Außerdem hat die Methode den Vorteil, daß Benutzerrechte und
andere Dateiattribute bei der Übertragung erhalten
bleiben\footnote{Vorausgesetzt natürlich, daß der Benutzer auf der entfernten
Seite über die nötigen Rechte verfügt.}.
Der Trick besteht darin, auf einer Seite der Verbindung etwas mit \texttt{tar}
einzupacken, dies durch eine Pipe auf die andere Seite der Verbindung zu
bringen und dort wieder zu entpacken.
Wenn dem Kommando \texttt{tar} an Stelle eines Dateinamens ein Minus-Zeichen
als Archiv gegeben wird, benutzt es~--~je nach der gewählten Aktion~--~die
Standard-Ein- bzw. -Ausgabe. Diese kann an ein weiteres \texttt{tar} übergeben
werden um wieder entpackt zu werden.
Ein Beispiel verdeutlicht diese Kopier-Fähigkeit:
\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
Pipe wird eine Subshell geöffnet. Das ist notwendig, da das empfangende
\texttt{tar} in einem anderen Verzeichnis laufen soll. In der Subshell wird
zunächst das Verzeichnis gewechselt. Dann liest ein \texttt{tar} von der
Standard-Eingabe und entpackt alles was er findet. Sobald keine Eingaben mehr
kommen, beendet sich der Prozeß mitsamt der Subshell.
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
\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.
Eine Seite der Pipe kann nämlich auch ohne Probleme auf einem entfernten
Rechner `stattfinden'. Kommandos wie \texttt{ssh} oder \texttt{rsh} (letzteres
nur unter Vorsicht einsetzen!) schlagen die Brücke zu einem anderen System,
dort wird entweder gepackt und versendet oder quasi die Subshell gestartet und
gelesen. Das sieht wie folgt aus:
\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:
\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 besteht darin, daß das Zielverzeichnis bei Bedarf erstellt
wird, bevor die Datei dort entpackt wird. Zur Erklärung: Die Variable
\texttt{\$PWD} wird, da sie nicht von Ticks `gesichert' wird, schon lokal durch
die Shell expandiert. An dieser Stelle erscheint also auf dem entfernten System
der Name des aktuellen Verzeichnisses auf dem lokalen System.
\section{Binaries inside} \section{Binaries inside}
TODO!!! Software wird meistens in Form von Paketen verteilt. Entweder handelt es sich
dabei um auf das Betriebssystem abgestimmte Installationspakete (rpm, deb, pkg
usw.), gepackte Archive (zip, tgz) oder Installationsprogramme. Unter
Unix-Systemen bietet sich für letztere die Shell als Trägersystem an.
Shell-Skripte sind mit wenigen Einschränkungen plattformunabhängig, sie können
also ohne vorherige Installations- oder Compilier-Arbeiten gestartet werden und
die Umgebung für das zu installierende Programm testen und / oder vorbereiten.
Abgesehen davon können Skripte mit den hier vorgestellten Techniken auch andere
Daten, z. B. Bilder oder Töne, enthalten.
Doch wie werden die~--~üblicherweise binären~--~Pakete auf das Zielsystem
gebracht?
Im Prinzip gibt es dafür zwei unterschiedliche Verfahren:
\subsection{Binäre Here-Dokumente} \subsection{Binäre Here-Dokumente}
\index{Here-Dokument}
TODO!!! Eine Möglichkeit ist es, die binäre Datei in Form eines Here-Dokuments
mitzuliefern. Da es aber in der Natur einer binären Datei liegt nicht-druckbare
Zeichen zu enthalten, kann die Datei mit Hilfe des Tools \texttt{uuencode}
vorbereitet werden. Das Tool codiert Eingabedateien so, daß sie nur noch
einfache Textzeichen enthalten.
Sehen wir uns das folgende einfache Beispiel an. Es ist etwas wild konstruiert
und nicht sehr sinnvoll, aber es zeigt das Prinzip.
\begin{lstlisting}
#!/bin/sh
echo "Das Bild wird ausgepackt..."
uudecode << 'EOF'
begin 644 icon.png
MB5!.1PT*&@H````-24A$4@```!8````6"`8```#$M&P[````"7!(67,```L3
M```+$P$`FIP8````!&=!34$``+&.?/M1DP```"!C2%)-``!Z)0``@(,``/G_
\end{lstlisting}
Nach einem Hinweis wird also das Here-Dokument als Eingabe für das Tool
\texttt{uudecode} benutzt. Erstellt wurde das Dokument mit einer Zeile der
folgenden Form:
\lstinline|uuencode icon.png icon.png|
Wie man sieht ist der Name der Datei in dem Here-Dokument enthalten. Die Datei
wird entpackt und unter diesem gespeichert. In der `realen Welt' muß an der
Stelle auf jeden Fall sichergestellt werden, daß keine existierenden Dateien
versehentlich überschrieben werden.
Um diesen Abschnitt nicht allzu lang werden zu lassen überspringen wir einen
Teil der Datei.
\begin{lstlisting}[firstnumber=38]
M#-""F4%,@%4.GUZ``"(*`6VW6!S#\>C_?/;__Q<R_S]<P/F7AXDA'I\>@``B
K!>E;2S-,]5!A7`,,U'0@GQ6?8H```P`#@&?)O'P'L0````!)14Y$KD)@@@``
`
end
EOF
if [ $? -ne 0 ]; then
echo "Fehler beim Auspacken der Datei"
exit 1
fi
display icon.png
\end{lstlisting}
Nach dem Entpacken wird noch der Exit-Code von \texttt{uudecode} überprüft und
im Fehlerfall eine Ausgabe gemacht. Im Erfolgsfall wird das Bild mittels
\texttt{display} angezeigt.
\subsection{Schwanz ab!} \subsection{Schwanz ab!}
TODO!!! Diese Variante basiert darauf, daß die binäre Datei ohne weitere Codierung an
das Shell-Skript angehängt wurde. Nachteil dieses Verfahrens ist, daß das
`abschneidende Kommando' nach jeder Änderung der Länge des Skriptes angepaßt
werden muß.
\section{Dateien, die es nicht gibt} Dabei gibt es zwei Methoden, die angehängte Datei wieder abzuschneiden. Die
einfachere Methode funktioniert mit \texttt{tail}:
TODO!!! \lstinline|tail -n +227 $0 > icon.png|
\subsection{Speichern in nicht existente Dateien} Dieses Beispiel geht davon aus, daß das Skript selbst 227 Zeilen umfaßt. Die
binäre Datei wurde mit einem Kommando wie \lstinline|cat icon.png >> skript.sh|
an das Skript angehängt.
TODO!!! Für die etwas kompliziertere Variante muß die Länge des eigentlichen
Skript-Teiles genau angepaßt werden. Wenn das Skript beispielsweise etwa 5,5kB
lang ist, müssen genau passend viele Leerzeilen oder Kommentarzeichen angehängt
werden, damit sich eine Länge von 6kB ergibt. Dann kann das Anhängsel mit dem
Kommando \texttt{dd} in der folgenden Form abgeschnitten werden:
\subsection{Daten aus einer Subshell hochreichen} \lstinline|dd bs=1024 if=$0 of=icon.png skip=6|
Das Kommando kopiert Daten aus einer Eingabe- in eine Ausgabedatei. Im
einzelnen wird hier eine Blockgröße (blocksize, bs) von 1024 Bytes festgelegt.
Dann werden Eingabe- und Ausgabedatei benannt, dabei wird als Eingabedatei
\texttt{\$0} und somit der Name des laufenden Skriptes benutzt. Schließlich
wird festgelegt, daß bei der Aktion die ersten sechs Block~--~also die ersten
sechs Kilobytes~--~übersprungen werden sollen.
Um es nochmal zu betonen: Diese beiden Methoden sind mit Vorsicht zu genießen.
Bei der ersten führt jede zusätzliche oder gelöschte Zeile zu einer kaputten
Ausgabedatei, bei der zweiten reichen schon einzelne Zeichen. In jedem Fall
sollte nach dem Auspacken noch einmal mittels \texttt{sum} oder \texttt{md5sum}
eine Checksumme gezogen und verglichen werden.
\section{Dateien, die es nicht gibt}\label{dateien_die_es_nicht_gibt}
Eine Eigenart der Behandlung von Dateien unter Unix besteht im Verhalten beim
Löschen. Gelöscht wird nämlich zunächst nur der Verzeichniseintrag. Der Inode,
also die Markierung im Dateisystem unter der die Datei gefunden werden kann,
besteht weiterhin. Er wird erst dann freigegeben, wenn er nicht mehr
referenziert wird. Physikalisch besteht die Datei also noch, sie wird lediglich
im Verzeichnis nicht mehr angezeigt.
Hat ein Prozeß die Datei noch in irgendeiner Form geöffnet, kann er weiter
darauf zugreifen. Erst wenn er die Datei schließt ist sie tatsächlich und
unwiederbringlich `weg'.
Dieser Effekt der `nicht existenten Dateien' läßt sich an verschiedenen Stellen
geschickt einsetzen.
\subsection{Daten aus einer Subshell hochreichen}\label{daten_hochreichen}
Ein immer wieder auftretendes und oft sehr verwirrendes Problem ist, daß
Variablen die in einer Subshell definiert wurden außerhalb dieser nicht
sichtbar sind (siehe Abschnitt \ref{subshellschleifen}). Dies ist um so
ärgerlicher, als daß Subshells auch bei vergleichsweise einfachen Pipelines
geöffnet werden.
Ein Beispiel für ein mißlingendes Skriptfragment wäre das folgende:
\begin{lstlisting}
nCounter=0
cat datei.txt | while read VAR; do
nCounter=`expr $nCounter + 1`
done
echo "nCounter=$nCounter"
\end{lstlisting}
Die Variable nCounter wird mit 0 initialisiert. Dann wird eine Datei per Pipe
in eine \texttt{while}-Schleife geleitet. Innerhalb der Schleife wird für jede
eingehende Zeile die Variable hochgezählt. Am Ende der Schleife enthält die
Variable tatsächlich den korrekten Wert, aber da die Pipe eine Subshell
geöffnet hat ist der Wert nach Beendigung der Schleife nicht mehr sichtbar. Das
\texttt{echo}-Kommando gibt die Zahl 0 aus.
Es gibt mehrere Ansätze, diesem Problem zu begegnen. Am einfachsten wäre es in
diesem Fall, dem Rat aus Abschnitt \ref{subshellschleifen} zu folgen und die
Subshell geschickt zu vermeiden. Doch das ist leider nicht immer möglich. Wie
geht man in solchen Fällen vor?
Bei einfachen Zahlenwerten könnte beispielsweise ein Rückgabewert helfen.
Komplexere Informationen können in eine temporäre Datei geschrieben werden, die
danach geparst werden müßte. Wenn die Informationen in Zeilen der Form
\lstinline|VARIABLE="Wert"| gespeichert werden, kann die Datei einfach mittels
\texttt{source} (Abschnitt \ref{source}) oder einem Konstrukt der folgenden Art
gelesen werden:
\lstinline|eval `cat tempfile`|
Und genau mit dieser Überlegung kommen wir zu einem eleganten~--~wenn auch
nicht ganz einfachen~--~Trick.
Anstatt die Daten in eine temporäre Datei zu schreiben, wo sie womöglich durch
andere Prozesse verändert oder ausgelesen werden könnten, kann man sie auch in
`nicht existente' Dateien schreiben. Das folgende Beispiel demonstriert das
Verfahren:
\begin{lstlisting}
#!/bin/sh -x
TMPNAME="/tmp/`date '+%Y%m%d%H%M%S'`$$.txt"
exec 3> "$TMPNAME"
exec 4< "$TMPNAME"
rm -f "$TMPNAME"
\end{lstlisting}
Bis hierher wurde zunächst eine temporäre Datei angelegt. Die Filehandles 3 und
4 wurden zum Schreiben bzw. Lesen mit dieser Datei verbunden. Daraufhin wurde
die Datei entfernt. Die Filehandles verweisen weiterhin auf die Datei, obwohl
sie im Dateisystem nicht mehr sichtbar ist.
Kommen wir zum nützlichen Teil des Skriptes:
\begin{lstlisting}[firstnumber=6]
nCounter=0
cat datei.txt | ( while read VAR; do
while read VAR; do
nCounter=`expr $nCounter + 1`
done
echo "nCounter=$nCounter"
) >&3
\end{lstlisting}
Hier wurde wieder die Variable nCounter initialisiert und in der Subshell die
Zeilen gezählt wie im ersten Beispiel. Allerdings wurde explizit eine Subshell
um die Schleife gestartet. Dadurch steht die in der Schleife hochgezählte
Variable auch nach Beendigung der Schleife zur Verfügung, allerdings immernoch
nur in der Subshell. Um das zu ändern, wird in Zeile 11 der Wert ausgegeben.
Die Ausgaben der Subshell werden in den oben erstellen Deskriptor umgeleitet.
\begin{lstlisting}[firstnumber=13]
echo "(vor eval) nCounter=$nCounter"
eval `cat <&4`
echo "(nach eval) nCounter=$nCounter"
\end{lstlisting}
Das \texttt{echo}-Kommando in Zeile 13 beweist, daß der Wert von nCounter
tatsächlich außerhalb der Subshell nicht zur Verfügung steht. Zunächst.
In Zeile 14 wird dann die ebenfalls oben schon angesprochene
\texttt{eval}-Zeile benutzt, um die Informationen aus dem Filedeskriptor zu
lesen, die die Schleife dort hinterlassen hat.
Abschließend zeigt die Zeile 15, daß der Transport tatsächlich funktioniert
hat, die Variable nCounter ist mit dem Wert aus der Subshell belegt.
\subsection{Dateien gleichzeitig lesen und schreiben}\label{lesen_und_schreiben}
Es kommt vor, daß man eine Datei bearbeiten möchte, die hinterher aber wieder
unter dem gleichen Namen zur Verfügung stehen soll. Beispielsweise sollen alle
Zeilen aus einer Datei entfernt werden, die nicht das Wort \textit{wichtig}
enthalten.
Der erste Versuch an der Stelle wird etwas in der Form
\lstinline|grep wichtig datei.txt > datei.txt|
sein. Das kann funktionieren, es kann aber auch in die sprichwörtliche Hose
gehen. Das Problem an der Stelle ist, daß die Datei an der Stelle gleichzeitig
zum Lesen und zum Schreiben geöffnet wird. Das Ergebnis ist undefiniert.
Eine Elegante Lösung besteht darin, einen Filedeskriptor auf die Quelldatei zu
legen und diese dann zu löschen. Die Datei wird erst dann wirklich aus dem
Dateisystem entfernt, wenn kein Deskriptor mehr auf sie zeigt. Dann kann aus
dem gerade angelegten Deskriptor gelesen werden, während eine neue Datei unter
dem alten Namen angelegt wird:
\begin{lstlisting}
#!/bin/sh
FILE=datei.txt
exec 3< "$FILE"
rm "$FILE"
grep "wichtig" <&3 > "$FILE"
\end{lstlisting}
Allerdings sollte man bei dieser Methode beachten, daß man im Falle eines
Fehlers die Quelldaten verliert, da die Datei ja bereits gelöscht wurde.
\section{Auf der Lauer: Wachhunde}\label{wachhunde}\index{Watchdog}
Es kommt vor, daß man einen Prozeß startet, bei dem man sich nicht sicher sein
kann daß er sich auch in absehbarer Zeit wieder beendet. Beispielsweise kann
der Timeout für einen Netzwerkzugriff deutlich höher liegen als erwünscht, und
wenn der `gegnerische' Dienst nicht antwortet bleibt einem nur zu warten.
Es sei denn, man legt einen geeigneten Wachhund\footnote{Der englische Begriff
`Watchdog' ist in diesem Zusammenhang wahrscheinlich geläufiger...} auf die
Lauer, der im Notfall rettend eingreift. In einem Shell-Skript könnte das wie
folgt aussehen:
\begin{lstlisting}
#!/bin/sh
timeout=5
ping 192.168.0.254 &
cmdpid=$!
\end{lstlisting}
Bis hierher nichts aufregendes. Eine Variable wird mit dem Timeout belegt, also
mit der Anzahl an Sekunden nach denen der zu überwachende Prozeß unterbrochen
werden soll. Dann wird der zu überwachende Prozeß gestartet und mittels \& in
den Hintergrund geschickt. Die Prozeß-ID des Prozesses wird in der Variablen
cmdpid gesichert.
\begin{lstlisting}[firstnumber=5]
(sleep $timeout; kill -9 $cmdpid) &
watchdogpid=$!
\end{lstlisting}
In Zeile 5 findet sich der eigentliche Watchdog. Hier wird eine Subshell
gestartet, in der zunächst der oben eingestellte Timeout abgewartet und dann
der zu überwachende Prozeß getötet wird. Diese Subshell wird ebenfalls mit \&
in den Hintergrund geschickt. Die ID der Subshell wird in der Variablen
watchdogpid gesichert.
\begin{lstlisting}[firstnumber=7]
wait $cmdpid
kill $watchdogpid > /dev/null 2>&1
exit 0
\end{lstlisting}
Dann wird durch ein \texttt{wait}\index{wait=\texttt{wait}} darauf gewartet,
daß sich der überwachte Prozeß beendet. Dabei würde \texttt{wait} bis in alle
Ewigkeit warten, wäre da nicht der Watchdog in der Subshell. Wenn dem die
Ausführung zu lange dauert, sorgt er dafür daß der Prozeß beendet wird.
Kommt der überwachte Prozeß aber rechtzeitig zurück, sorgt \texttt{kill} in
Zeile 8 dafür daß der Wachhund `eingeschläfert' wird.
Auf diese Weise ist sichergestellt, daß der \texttt{ping} auf keinen Fall
länger als fünf Sekunden läuft.
\section{Unter Druck: Auf Tasten warten}\label{tastendruck}\index{Tastendruck}
Oft baut man in längere Ausgaben eine Art Warte-Prompt im Stile von `Bitte
Enter drücken um fortzufahren' ein. Gewartet wird dann mit Hilfe des
\texttt{read}-Kommandos\index{read=\texttt{read}}.
Will man nicht nur auf den Druck der Enter-Taste reagieren, sondern auf einen
beliebigen Tastendruck, eignet sich das folgende Konstrukt:
\begin{lstlisting}
stty raw -echo
inputchar=`dd if=/dev/tty bs=1 count=1 2> /dev/null`
stty sane
\end{lstlisting}
Zur Erklärung: Mit dem Kommando \texttt{stty}\index{stty=\texttt{stty}} kann
ein Terminal konfiguriert werden. Dabei kann es sich sowohl um eine Leitung wie
die serielle Schnittstelle des Rechners handeln, als auch um das Terminal an
dem der Benutzer sitzt. Jedes Terminal hat eine Reihe von Eigenschaften.
Mittels \lstinline|stty raw -echo| wird das Terminal in einen passenden Modus
geschaltet. Das \texttt{-echo} sorgt dafür, daß eingegebene Zeichen nicht in
der Konsole wiedergegeben werden.
Danach wird mit \texttt{dd}\index{dd=\texttt{dd}} genau ein Zeichen eingelesen.
Die Fehlerausgabe von \texttt{dd} wird dabei nach /dev/null umgeleitet, da
ansonsten auf der Konsole die Erfolgsmeldungen \textit{1+0 Datensätze ein, 1+0
Datensätze aus} erscheinen würden. Das gelesene Zeichen wird in der Variablen
\texttt{\$inputchar} gesichert und steht somit zur Verfügung.
Nach dem Einlesevorgang wird die Konsole schließlich mittels
\lstinline|stty sane| wieder in einen benutzbaren Zustand zurückversetzt.
TODO!!!

235
shell.tex
View File

@ -1,3 +1,4 @@
% $Id$
%============================================================================== %==============================================================================
% LaTeX-Schema-Datei schema.tex % LaTeX-Schema-Datei schema.tex
%============================================================================== %==============================================================================
@ -6,50 +7,38 @@
% Vorspann % Vorspann
%============================================================================== %==============================================================================
\newif\ifpdf % Feststellen, ob wir PDF oder DVI
% erzeugen
\ifx\pdfoutput\undefined
\pdffalse % Wir haben kein PDFLaTeX
\else
\pdftrue % Wir haben PDFLaTeX
\fi
\ifpdf % PDF-Einstellungen
\pdfoutput=1
\pdfcompresslevel=9
\pdfinfo{
/Author (Ronald Schaten)
/CreationDate (D:20000301170300) % (D:YYYYMMDDhhmmss)
% /ModDate (D:19980212201000) % ModDate is similar
/Title (Shell-Programmierung)
/Subject (Shell-Programmierung)
/Keywords (Shell)
}
\pdfcatalog{ % Catalog dictionary of PDF output.
/PageMode /UseOutlines
/URI (http://www.fi.muni.cz/)
}
\else % Nicht-PDF-Einstellungen
\fi
% Dokumentstil für Buch % Dokumentstil für Buch
\documentclass[a4paper,12pt,draft,twoside]{book} \documentclass[
a4paper, % Seitenformat A4
12pt, % 12-Punkt-Schrift
BCOR.5cm, % 0,5cm Rand für die Bindung
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
]{scrbook}
\usepackage{german} % deutsches Paket für Umlaute \usepackage{german} % deutsches Paket für Umlaute
%\usepackage{t1enc} % DC-Font mit 8 Bit verwenden
\usepackage[latin1]{inputenc} % Codepage latin1 \usepackage[latin1]{inputenc} % Codepage latin1
%\usepackage{graphicx} % Grafikpaket für Bilder laden \usepackage{mathptmx} % Andere Schriften benutzen
\usepackage[scaled=.90]{helvet}
\usepackage{courier}
\usepackage{pifont} % für dinglist (Icon neben Text)
%\usepackage[dvips]{graphicx} % Grafikpaket für Bilder laden
%\usepackage{epstopdf} % .eps bei Bedarf nach .pdf wandeln
%\DeclareGraphicsRule{.tif}{bmp}{}{} % Grafikformate %\DeclareGraphicsRule{.tif}{bmp}{}{} % Grafikformate
\usepackage{tabularx} % für Tabellen über die Seitenbreite
\usepackage{longtable} % für Tabellen über die Seitenbreite
\usepackage{supertabular} % für Tabellen über die Seitenbreite
\usepackage{ltxtable} % für Tabellen über die Seitenbreite
\ifpdf % PDF-Einstellungen %\usepackage{tabularx} % für Tabellen über die Seitenbreite
\usepackage{thumbpdf} %\usepackage{longtable} % für Tabellen über die Seitenbreite
\else % Nicht-PDF-Einstellungen %\usepackage{supertabular} % für Tabellen über die Seitenbreite
\fi \usepackage{ltxtable} % für Tabellen über die Seitenbreite
\usepackage{makeidx} % Index wird später eingefügt \usepackage{makeidx} % Index wird später eingefügt
\makeindex % durch \printindex \makeindex % durch \printindex
@ -58,23 +47,39 @@
\usepackage{fancybox} % Kästchen für Tastendarstellung \usepackage{fancybox} % Kästchen für Tastendarstellung
\usepackage{fancyhdr} % Kopf- und Fußzeilen %\usepackage{moreverb} % Für Listings
\pagestyle{fancy} \usepackage{listings} % Für Listings
\renewcommand{\chaptermark}[1]{\markboth{#1}{}} \lstset{
\renewcommand{\sectionmark}[1]{\markright{\thesection\ #1}} extendedchars=true,
\fancyhf{} backgroundcolor=\color[gray]{0.95},
\fancyhead[RE]{\bfseries\leftmark} basicstyle=\ttfamily\footnotesize,
\fancyhead[LO]{\bfseries\rightmark} numbers=left,
\fancyhead[RO,LE]{\bfseries\thepage} numberstyle=\scriptsize,
\renewcommand{\headrulewidth}{0.5pt} stepnumber=2,
\addtolength{\headheight}{2.5pt} numbersep=5pt
\fancypagestyle{plain}{
\fancyhead{}
\renewcommand{\headrulewidth}{0pt}
\fancyfoot[C]{\bfseries\thepage}
} }
\usepackage{moreverb} % Für Listings
% Für PDF
\usepackage[
pdftitle = {Shell-Programmierung},
pdfsubject = {Programmierung~der~Unix-Shell},
pdfkeywords = {shell~programmierung},
pdfauthor = {Ronald~Schaten},
bookmarks,
bookmarksopen,
bookmarksopenlevel = 1,
bookmarksnumbered,
linktocpage,
colorlinks,
linkcolor = black,
urlcolor = black
]{hyperref}
%\pdfinfo{/CreationDate (D:20000301170300-01'00')} % (D:YYYYMMDDhhmmss)
%% /ModDate (D:19980212201000) % ModDate is similar
\newcommand{\STRUT}{\rule{0in}{3ex}} % Ein vertikaler Abstand für Tabellen \newcommand{\STRUT}{\rule{0in}{3ex}} % Ein vertikaler Abstand für Tabellen
@ -87,56 +92,149 @@
\begin{document} % hiermit muß jedes Dokument beginnen \begin{document} % hiermit muß jedes Dokument beginnen
\vspace*{.75in} % Die Titelseite % Syntax-Boxen (sybox) definieren:
\fboxsep 1.36mm
\definecolor{g1}{gray}{0.95}
\newsavebox{\syntaxbox}
\newenvironment{sybox}
{\begin{lrbox}{\syntaxbox}
\begin{minipage}{\textwidth}}
{\end{minipage}
\end{lrbox}
{\fcolorbox{g1}{g1}
{\parbox{\textwidth}{\usebox{\syntaxbox}\hfill\hbox{}}}}}
\vspace*{.6in} % Die Titelseite
\thispagestyle{empty} \thispagestyle{empty}
\begin{centering} \begin{centering}
\rule{5in}{.04in}\\ \vspace{.25in} \rule{5in}{.04in}\\ \vspace{.25in}
\Huge {\bf SHELL\\ \vspace{.4in} PROGRAMMIERUNG}\\ \vspace{.1in} \Huge {\bf SHELL\\ \vspace{.4in} PROGRAMMIERUNG}\\ \vspace{.1in}
\rule{5in}{.04in}\\ \vspace{.5in} \rule{5in}{.04in}\\ \vspace{.6in}
\large v2.0.1\\
\large \today\\ \vspace{.75in} \large \today\\ \vspace{.75in}
\large von\\ \vspace{.3in} \large von\\ \vspace{.3in}
\LARGE {\bf Ronald Schaten} \\ \vspace{.6in} \LARGE {\bf Ronald Schaten} \\ \vspace{.6in}
\large ronald@schatenseite.de\\ \large ronald@schatenseite.de\\
\large http://www.schatenseite.de/\\ \large http://www.schatenseite.de/\\
\end{centering} \end{centering}
\newpage \newpage
\thispagestyle{empty} % eine Leerseite \thispagestyle{empty} % eine Leerseite
\begin{quote}
\emph{The best way to become acquainted with a subject is to write a book about it.
\begin{flushright}(Benjamin Disraeli)\end{flushright}}
\end{quote}
~\vfill ~\vfill
\footnotesize \footnotesize
Copyright \copyright{} 2001 Ronald Schaten (\texttt{ronald@schatenseite.de})\bigskip Die aktuellste Version dieses Dokumentes befindet sich auf
\href{http://www.schatenseite.de/}{http://www.schatenseite.de/}.
Die aktuellste Version dieses Dokumentes befindet sich im World Wide Web auf meiner Homepage (\texttt{http://www.schatenseite.de/}).\bigskip 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 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.}
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.}\bigskip Copyright \copyright{} 2000-2005 Ronald Schaten (ronald@schatenseite.de)
Ich danke folgenden Personen, die mir bei der Durchsicht behilflich waren und durch ihre konstruktive Kritik zu Verbesserungen beigetragen haben (in chronologischer Reihenfolge ihres Eingreifens): \textbf{Dieses Dokument steht unter der Creative Commons Lizenz.} Die
Weiterverbreitung ist unter gewissen Bedingungen (Namensnennung, keine
kommerzielle Nutzung und keine Bearbeitung) erlaubt und gewünscht. Ich habe
diese Lizenz gewählt um sicherzustellen daß Verbesserungen am Inhalt des
Dokumentes bei mir ankommen, damit ich sie in die `Hauptversion' einfließen
lassen kann.
Die Lizenzbedingungen stehen unter
\href{http://creativecommons.org/licenses/by-nc-nd/2.0/de/}{http://creativecommons.org/licenses/by-nc-nd/2.0/de/}.
% <!-- Creative Commons-Lizenzvertrag -->
% <a rel="license"
% href="http://creativecommons.org/licenses/by-nc-nd/2.0/de/"><img alt="Creative
% Commons-Lizenzvertrag" border="0"
% src="http://creativecommons.org/images/public/somerights20.gif" /></a><br />
% Diese Inhalt ist unter einer <a rel="license"
% href="http://creativecommons.org/licenses/by-nc-nd/2.0/de/">Creative
% Commons-Lizenz</a> lizenziert.
% <!-- /Creative Commons-Lizenzvertrag -->
%
%
% <!--
%
% <rdf:RDF xmlns="http://web.resource.org/cc/"
% xmlns:dc="http://purl.org/dc/elements/1.1/"
% xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
% <Work rdf:about="">
% <dc:title>Shell&amp;#45;Programmierung</dc:title>
% <dc:date>2005</dc:date>
% <dc:description>Einführung in die
% Shell&amp;#45;Programmierung</dc:description>
% <dc:creator><Agent>
% <dc:title>Ronald Schaten</dc:title>
% </Agent></dc:creator>
% <dc:rights><Agent>
% <dc:title>Ronald Schaten</dc:title>
% </Agent></dc:rights>
% <dc:type rdf:resource="http://purl.org/dc/dcmitype/Text" />
% <license rdf:resource="http://creativecommons.org/licenses/by-nc-nd/2.0/de/"
% />
% </Work>
%
% <License rdf:about="http://creativecommons.org/licenses/by-nc-nd/2.0/de/">
% <permits rdf:resource="http://web.resource.org/cc/Reproduction" />
% <permits rdf:resource="http://web.resource.org/cc/Distribution" />
% <requires rdf:resource="http://web.resource.org/cc/Notice" />
% <requires rdf:resource="http://web.resource.org/cc/Attribution" />
% <prohibits rdf:resource="http://web.resource.org/cc/CommercialUse" />
% </License>
%
% </rdf:RDF>
%
% -->
Ich danke folgenden Personen, die mir bei der Durchsicht behilflich waren und
durch ihre konstruktive Kritik zu Verbesserungen beigetragen haben (in
chronologischer Reihenfolge ihres Eingreifens):
\begin{list}{$\bullet$}{\itemsep=-0.5cm} \begin{list}{$\bullet$}{\itemsep=-0.5cm}
\item Jürgen Ilse (\texttt{ilse@asys-h.de})\\ \item Jürgen Ilse (ilse@asys-h.de)\\
\item Christian Perle (\texttt{christian.perle@tu-clausthal.de})\\ \item Christian Perle (christian.perle@tu-clausthal.de)\\
\item Andreas Metzler (\texttt{ametzler@downhill.at.eu.org})\\ \item Andreas Metzler (ametzler@downhill.at.eu.org)\\
\item Johannes Kolb (\texttt{johannes.kolb@web.de})\\ \item Johannes Kolb (johannes.kolb@web.de)\\
\item Falk Friedrich (falk@gmx.de)\\
\item Kai Thöne (kai.thoene@gmx.de)\\
\end{list} \end{list}
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. 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.
Dieses Dokument entstand unter Verwendung von Linux, vim und \LaTeX. Dank an
deren Entwickler.
\normalsize \normalsize
\newpage \newpage
\pagenumbering{roman} \pagenumbering{roman}
\renewcommand{\headrulewidth}{0.5pt} %\renewcommand{\headrulewidth}{0.5pt}
\setcounter{tocdepth}{3} \setcounter{tocdepth}{3}
\tableofcontents \tableofcontents
\newpage \newpage
\pagenumbering{arabic} \pagenumbering{arabic}
% Haupttextteil % Haupttextteil
\include{was_ist_die_shell} \include{was_ist_die_shell}
\include{wo_sind_unterschiede_zu_dos_batchdateien}
\include{wofuer_shell_programmierung} \include{wofuer_shell_programmierung}
\include{wie_sieht_ein_shell_skript_aus} \include{wie_sieht_ein_shell_skript_aus}
\include{nuetzliche_shell-kommandos} \include{werkzeugkasten}
\include{wo_sind_unterschiede_zu_dos_batchdateien}
\appendix \appendix
\include{beispiele} \include{beispiele}
\include{schmutzige_tricks} \include{schmutzige_tricks}
\include{quellen} \include{quellen}
\include{todo}
\printindex % Index einfügen \printindex % Index einfügen
@ -146,11 +244,6 @@ Und ich bitte alle Leser, auf eventuelle Fehler zu achten und mich darauf aufmer
\end{document} \end{document}
\ifpdf % PDF-Einstellungen
\bye
\else % Nicht-PDF-Einstellungen
\fi
%============================================================================== %==============================================================================
% Ende von schema.tex % Ende von schema.tex
%============================================================================== %==============================================================================

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -10,9 +11,10 @@
\textsl{Befehl}\texttt{ \&} & Ausführung von \textsl{Befehl} im Hintergrund \tabularnewline\STRUT \textsl{Befehl}\texttt{ \&} & Ausführung von \textsl{Befehl} im Hintergrund \tabularnewline\STRUT
\textsl{Befehl1}\texttt{ ; }\textsl{Befehl2} & Befehlsfolge, führt mehrere Befehle nacheinander aus \tabularnewline\STRUT \textsl{Befehl1}\texttt{ ; }\textsl{Befehl2} & Befehlsfolge, führt mehrere Befehle nacheinander aus \tabularnewline\STRUT
\texttt{(}\textsl{Befehl1}\texttt{ ; }\textsl{Befehl2}\texttt{)} & Subshell\index{Subshell}, behandelt \textsl{Befehl1} und \textsl{Befehl2} als Befehlsblock und führt sie in einer Subshell aus \tabularnewline\STRUT \texttt{(}\textsl{Befehl1}\texttt{ ; }\textsl{Befehl2}\texttt{)} & Subshell\index{Subshell}, behandelt \textsl{Befehl1} und \textsl{Befehl2} als Befehlsblock und führt sie in einer Subshell aus \tabularnewline\STRUT
\texttt{\{ }\textsl{Befehl1}\texttt{ ; }\textsl{Befehl2}\texttt{ \}} & Befehlsblock; alle Befehle werden in der momentanen Shell ausgeführt, aber die Ausgaben werden behandelt, als ob nur ein Befehl ausgeführt würde \tabularnewline\STRUT \texttt{\{ }\textsl{Befehl1}\texttt{ ; }\textsl{Befehl2}\texttt{; \}} & Befehlsblock; alle Befehle werden in der momentanen Shell ausgeführt, aber die Ausgaben werden behandelt, als ob nur ein Befehl ausgeführt würde \tabularnewline\STRUT
\textsl{Befehl1}\texttt{ | }\textsl{Befehl2} & Pipe\index{Pipe}, verwendet die Ausgabe von \textsl{Befehl1} als Eingabe für \textsl{Befehl2} \tabularnewline\STRUT \textsl{Befehl1}\texttt{ | }\textsl{Befehl2} & Pipe\index{Pipe}, verwendet die Ausgabe von \textsl{Befehl1} als Eingabe für \textsl{Befehl2} \tabularnewline\STRUT
\textsl{Befehl1}\texttt{ `}\textsl{Befehl2}\texttt{`} & Befehls-Substitution, verwendet die Ausgabe von \textsl{Befehl2} als Argumente\index{Parameter}\index{Argument|see{Parameter}} für \textsl{Befehl1} \tabularnewline\STRUT \textsl{Befehl1}\texttt{ `}\textsl{Befehl2}\texttt{`} & Befehls-Substitution, verwendet die Ausgabe von \textsl{Befehl2} als Argumente\index{Parameter}\index{Argument|see{Parameter}} für \textsl{Befehl1} \tabularnewline\STRUT
\textsl{Befehl1}\texttt{ \$(}\textsl{Befehl2}\texttt{)} & Befehls-Substitution, andere Schreibweise\tabularnewline\STRUT
\textsl{Befehl1}\texttt{ \&\& }\textsl{Befehl2} & AND\index{AND}, führt zuerst \textsl{Befehl1} und dann (wenn \textsl{Befehl1} erfolgreich war) \textsl{Befehl2} aus\footnote{Einen ähnlichen Mechanismus kennt man aus verschiedenen Programmiersprachen unter dem Begriff \textsl{Kurzschlußauswertung}\index{Kurzschlußauswertung} bzw. \textsl{lazy evaluation}\index{Lazy Evaluation|see{Kurzschlußauswertung}}.} \tabularnewline\STRUT \textsl{Befehl1}\texttt{ \&\& }\textsl{Befehl2} & AND\index{AND}, führt zuerst \textsl{Befehl1} und dann (wenn \textsl{Befehl1} erfolgreich war) \textsl{Befehl2} aus\footnote{Einen ähnlichen Mechanismus kennt man aus verschiedenen Programmiersprachen unter dem Begriff \textsl{Kurzschlußauswertung}\index{Kurzschlußauswertung} bzw. \textsl{lazy evaluation}\index{Lazy Evaluation|see{Kurzschlußauswertung}}.} \tabularnewline\STRUT
\textsl{Befehl1}\texttt{ || }\textsl{Befehl2} & OR\index{OR}, entweder \textsl{Befehl1} ausführen oder \textsl{Befehl2} (Wenn \textsl{Befehl1} nicht erfolgreich war) \textsl{Befehl1}\texttt{ || }\textsl{Befehl2} & OR\index{OR}, entweder \textsl{Befehl1} ausführen oder \textsl{Befehl2} (Wenn \textsl{Befehl1} nicht erfolgreich war)
\end{longtable} \end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -10,7 +11,8 @@
\texttt{\$ nroff }\textsl{Datei}\texttt{ \&} & Formatiert die \textsl{Datei} im Hintergrund \tabularnewline\STRUT \texttt{\$ nroff }\textsl{Datei}\texttt{ \&} & Formatiert die \textsl{Datei} im Hintergrund \tabularnewline\STRUT
\texttt{\$ cd; ls} & Sequentieller Ablauf \tabularnewline\STRUT \texttt{\$ cd; ls} & Sequentieller Ablauf \tabularnewline\STRUT
\texttt{\$ (date; who; pwd) > logfile}\index{!>=\texttt{!>}} & Führt die Befehle in einer Subshell\index{Subshell} aus und lenkt alle Ausgaben um \tabularnewline\STRUT \texttt{\$ (date; who; pwd) > logfile}\index{!>=\texttt{!>}} & Führt die Befehle in einer Subshell\index{Subshell} aus und lenkt alle Ausgaben um \tabularnewline\STRUT
\texttt{\$ \{ date; who; pwd \} > logfile}\index{!>=\texttt{!>}} & Lenkt alle Ausgaben um \tabularnewline\STRUT \texttt{\$ \{ date; who; pwd; \} > logfile}\index{!>=\texttt{!>}} & Lenkt alle Ausgaben um \tabularnewline\STRUT
\texttt{\$ time \{ date; who; pwd; \}}\index{time=\texttt{time}} & Summiert die Laufzeit der drei Kommandos\tabularnewline\STRUT
\texttt{\$ sort }\textsl{Datei}\texttt{ | lp} & Sortiert die \textsl{Datei} und druckt sie\index{sort=\texttt{sort}} \tabularnewline\STRUT \texttt{\$ sort }\textsl{Datei}\texttt{ | lp} & Sortiert die \textsl{Datei} und druckt sie\index{sort=\texttt{sort}} \tabularnewline\STRUT
\texttt{\$ vi `grep -l ifdef *.c`}\index{*=\texttt{*}}\index{grep=\texttt{grep}} & Editiert die mittels grep gefundenen Dateien \tabularnewline\STRUT \texttt{\$ vi `grep -l ifdef *.c`}\index{*=\texttt{*}}\index{grep=\texttt{grep}} & Editiert die mittels grep gefundenen Dateien \tabularnewline\STRUT
\texttt{\$ grep }\textsl{XX Datei}\texttt{ \&\& lp }\textsl{Datei}\index{grep=\texttt{grep}} & Druckt die \textsl{Datei}, wenn sie \textsl{XX} enthält\index{AND} \tabularnewline\STRUT \texttt{\$ grep }\textsl{XX Datei}\texttt{ \&\& lp }\textsl{Datei}\index{grep=\texttt{grep}} & Druckt die \textsl{Datei}, wenn sie \textsl{XX} enthält\index{AND} \tabularnewline\STRUT

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,29 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\textsl{Seitenweises Formatieren der Dateien, die auf der Befehlszeile angegeben wurden, und speichern des jeweiligen Ergebnisses:}} \\
\multicolumn{2}{|X|}{\texttt{for file do}} \\
\multicolumn{2}{|X|}{\texttt{~pr \$file > \$file.tmp~~\# pr: Formatiert Textdateien}\index{!>=\texttt{!>}}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\multicolumn{2}{|X|}{\STRUT\textsl{Durchsuche Kapitel zur Erstellung einer Wortliste (wie \texttt{fgrep -f}):}} \\
\multicolumn{2}{|X|}{\texttt{for item in `cat program\_list`~~\# cat: Datei ausgeben}\index{cat=\texttt{cat}}\index{Backticks}} \\
\multicolumn{2}{|X|}{\texttt{do}} \\
\multicolumn{2}{|X|}{\texttt{~echo \dq Pruefung der Kapitel auf\dq}\index{Anführungszeichen}} \\
\multicolumn{2}{|X|}{\texttt{~echo \dq Referenzen zum Programm \$item ...\dq}\index{Anführungszeichen}} \\
\multicolumn{2}{|X|}{\texttt{~grep -c \dq\$item.[co]\dq~chap*~~\# grep: nach Muster\index{Mustererkennung} suchen}\index{[abc]=\texttt{[}\textsl{abc}\texttt{]}}\index{Anführungszeichen}\index{grep=\texttt{grep}}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\multicolumn{2}{|X|}{\STRUT\textsl{Ermittle einen Ein-Wort-Titel aus jeder Datei und verwende ihn als neuen Dateinamen:}} \\
\multicolumn{2}{|X|}{\texttt{for file do}} \\
\multicolumn{2}{|X|}{\texttt{~name=`sed -n 's/NAME: //p' \$file`}\index{!==\texttt{!=}}\index{Backticks}\index{Ticks}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~\# sed: Skriptsprache zur}\index{sed=\texttt{sed}}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~\# Textformatierung}} \\
\multicolumn{2}{|X|}{\texttt{~mv \$file \$name~~\# mv: Datei verschieben}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~~~~~~~~\# bzw. umbenennen}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\end{longtable}

View File

@ -1,16 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{count () \{}} \\
\multicolumn{2}{|X|}{\texttt{~ls -1 | wc -l~~\# ls: Liste aller Dateien im Verzeichnis}\index{Pipe}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~~~~~~~\#~~~~~Mit Parameter -1 einspaltig}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~~~~~~~\# wc: Word-Count, zählt Wörter}\index{wc=\texttt{wc}}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~~~~~~~\#~~~~~Mit Parameter -l Zeilen}} \\
\multicolumn{2}{|X|}{\texttt{\}}} \\
\end{longtable}

View File

@ -1,16 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\textsl{Füge eine 0 vor Zahlen kleiner 10 ein:}} \\
\multicolumn{2}{|X|}{\texttt{if [ \$counter -lt 10 ]; then}\index{;=\texttt{;}}} \\
\multicolumn{2}{|X|}{\texttt{~number=0\$counter; else number=\$counter; fi}\index{!==\texttt{!=}}} \\
\multicolumn{2}{|X|}{\STRUT\textsl{Lösche ein Verzeichnis, wenn es existiert:}} \\
\multicolumn{2}{|X|}{\texttt{if [ -d \$dir ]; then}\index{!!=\texttt{!!}}\index{;=\texttt{;}}} \\
\multicolumn{2}{|X|}{\texttt{~rmdir \$dir; fi~~\# rmdir: Verzeichnis löschen}} \\
\end{longtable}

View File

@ -1,13 +0,0 @@
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{\$ ls neu*} & Listet alle Dateien, die mit `neu' anfangen \tabularnewline\STRUT
\texttt{\$ ls neu?} & Listet `neuX', `neu4', aber nicht `neu10' \tabularnewline\STRUT
\texttt{\$ ls [D-R]*} & Listet alle Dateien, die mit einem Großbuchstaben\index{Großbuchstaben}\footnote{Natürlich wird in Shell-Skripten --- wie überall in der Unix-Welt --- zwischen Groß- und Kleinschreibung unterschieden.} zwischen D und R anfangen
\end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,15 +0,0 @@
\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

@ -1,18 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{\$ echo 'Ticks \dq schützen\dq~Anführungszeichen'}} \\
\multicolumn{2}{|X|}{\texttt{Ticks \dq schützen\dq~Anführungszeichen}} \\
\multicolumn{2}{|X|}{\STRUT\texttt{\$ echo \dq Ist dies ein \textbackslash\dq Sonderfall\textbackslash\dq ?\dq}} \\
\multicolumn{2}{|X|}{\texttt{Ist dies ein \dq Sonderfall\dq ?}} \\
\multicolumn{2}{|X|}{\STRUT\texttt{\$ echo \dq Sie haben `ls | wc -l` Dateien in `pwd`\dq}\index{wc=\texttt{wc}}} \\
\multicolumn{2}{|X|}{\texttt{Sie haben 43 Dateien in /home/rschaten}} \\
\multicolumn{2}{|X|}{\STRUT\texttt{\$ echo \dq Der Wert von \textbackslash\$x ist \$x\dq}} \\
\multicolumn{2}{|X|}{\texttt{Der Wert von \$x ist 100}} \\
\end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,17 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\textsl{Warten, bis sich der Administrator einloggt:}} \\
\multicolumn{2}{|X|}{\texttt{until who | grep \dq root\dq; do}\index{;=\texttt{;}}\index{Anführungszeichen}\index{who=\texttt{who}}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~\# who: Liste der Benutzer}} \\
\multicolumn{2}{|X|}{\texttt{~~~~~~~~~~\# grep: Suchen nach Muster}\index{Mustererkennung}} \\
\multicolumn{2}{|X|}{\texttt{~sleep 2~~\# sleep: warten}\index{sleep=\texttt{sleep}}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\multicolumn{2}{|X|}{\texttt{echo \dq Der Meister ist anwesend\dq}\index{Anführungszeichen}} \\
\end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -10,7 +11,7 @@
\texttt{\$ \textsl{h}=\textsl{hoch} \textsl{r}=\textsl{runter} \textsl{l}=} & Weist den drei Variablen Werte zu, wobei \textsl{l} einen leeren Wert erhält. \tabularnewline\STRUT \texttt{\$ \textsl{h}=\textsl{hoch} \textsl{r}=\textsl{runter} \textsl{l}=} & Weist den drei Variablen Werte zu, wobei \textsl{l} einen leeren Wert erhält. \tabularnewline\STRUT
\texttt{\$ echo \$\{h\}sprung} & Gibt \textsl{hochsprung} aus. Die Klammern müssen gesetzt werden, damit \textsl{h} als Variablenname erkannt werden kann. \tabularnewline\STRUT \texttt{\$ echo \$\{h\}sprung} & Gibt \textsl{hochsprung} aus. Die Klammern müssen gesetzt werden, damit \textsl{h} als Variablenname erkannt werden kann. \tabularnewline\STRUT
\texttt{\$ echo \$\{h-\$r\}} & Gibt \textsl{hoch} aus, da die Variable \textsl{h} belegt ist. Ansonsten würde der Wert von \textsl{r} ausgegeben. \tabularnewline\STRUT \texttt{\$ echo \$\{h-\$r\}} & Gibt \textsl{hoch} aus, da die Variable \textsl{h} belegt ist. Ansonsten würde der Wert von \textsl{r} ausgegeben. \tabularnewline\STRUT
\texttt{\$ echo \$\{tmp-`date`\}} & Gibt das aktuelle Datum aus, wenn die Variable \textsl{tmp} nicht gesetzt ist.\footnote{Der Befehl \texttt{date} gibt das Datum zurück.} \tabularnewline\STRUT \texttt{\$ echo \$\{tmp-`date`\}} & Gibt das aktuelle Datum aus, wenn die Variable \textsl{tmp} nicht gesetzt ist. \tabularnewline\STRUT
\texttt{\$ echo \$\{l:=\$r\}} & Gibt \textsl{runter} aus, da die Variable \textsl{l} keinen Wert enthält. Gleichzeitig wird \textsl{l} der Wert von \textsl{r} zugewiesen. \tabularnewline\STRUT \texttt{\$ echo \$\{l:=\$r\}} & Gibt \textsl{runter} aus, da die Variable \textsl{l} keinen Wert enthält. Gleichzeitig wird \textsl{l} der Wert von \textsl{r} zugewiesen. \tabularnewline\STRUT
\texttt{\$ echo \$l} & Gibt \textsl{runter} aus, da \textsl{l} jetzt den gleichen Inhalt hat wie \textsl{r}. \texttt{\$ echo \$l} & Gibt \textsl{runter} aus, da \textsl{l} jetzt den gleichen Inhalt hat wie \textsl{r}.
\end{longtable} \end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X l|} \begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,11 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{break }\textsl{[ n ]}} \\
\end{longtable}

View File

@ -1,15 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{case }\textsl{Wert}\texttt{ in}} \\
\multicolumn{2}{|X|}{\texttt{~}\textsl{Muster1}\texttt{) }\textsl{Befehle1}\texttt{;;}} \\
\multicolumn{2}{|X|}{\texttt{~}\textsl{Muster2}\texttt{) }\textsl{Befehle2}\texttt{;;}} \\
\multicolumn{2}{|X|}{\texttt{~\vdots}} \\
\multicolumn{2}{|X|}{\texttt{esac}} \\
\end{longtable}

View File

@ -1,11 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{continue }\textsl{[ n ]}} \\
\end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|X|X|X|X|} \begin{longtable}{|X|X|X|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,11 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{exit }\textsl{[ n ]}} \\
\end{longtable}

View File

@ -1,14 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{for }\textsl{x [}\texttt{ in }\textsl{Liste ]}} \\
\multicolumn{2}{|X|}{\texttt{do}} \\
\multicolumn{2}{|X|}{\texttt{~}\textsl{Befehle}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\end{longtable}

View File

@ -1,17 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{if }\textsl{Bedingung1}} \\
\multicolumn{2}{|X|}{\texttt{then }\textsl{Befehle1}} \\
\multicolumn{2}{|X|}{\textsl{[}\texttt{ elif }\textsl{Bedingung2}} \\
\multicolumn{2}{|X|}{\texttt{ then }\textsl{Befehle2 ]}} \\
\multicolumn{2}{|X|}{\texttt{ \vdots}} \\
\multicolumn{2}{|X|}{\textsl{[}\texttt{ else }\textsl{Befehle3 ]}} \\
\multicolumn{2}{|X|}{\texttt{fi}} \\
\end{longtable}

View File

@ -0,0 +1,21 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{FILENAME} & Der Name der aktuellen Eingabedatei, oder `-' wenn von der Standard-Eingabe gelesen wird\tabularnewline\STRUT
\texttt{FS} & Field Separator, das Trennzeichen nach dem die Felder unterteilt werden \tabularnewline\STRUT
\texttt{OFS} & Feldtrennzeichen für die Ausgabe \tabularnewline\STRUT
\texttt{RS} & Record Separator, das Trennzeichen nach dem Datensätze unterteilt werden \tabularnewline\STRUT
\texttt{ORS} & Datensatztrennzeichen für die Ausgabe \tabularnewline\STRUT
\texttt{NF} & Anzahl der Felder im aktuellen Datensatz \tabularnewline\STRUT
\texttt{NR} & Laufende Nummer des aktuellen Datensatzes \tabularnewline\STRUT
\texttt{OFMT} & Ausgabeformat für die Ausgabe von Zahlen und Strings, \tabularnewline\STRUT
\texttt{\$0} & Der komplette aktuelle Datensatz \tabularnewline\STRUT
\texttt{\$}\textsl{n} & Feld \textsl{n} des aktuellen Datensatzes
\end{longtable}

View File

@ -0,0 +1,16 @@
% $Id$
\begin{longtable}{|l|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
a-x & & Allen Benutzern werden die Ausführungsrechte genommen \tabularnewline\STRUT
ug+rw & & Dem Besitzer und der Gruppe werden Lese- und Schreibrechte gegeben \tabularnewline\STRUT
u=rw,go-rwx & 600 & Nur der Besitzer kann die Datei lesen und schreiben \tabularnewline\STRUT
u=rw,go=r & 644 & Der Besitzer darf lesen und schreiben, alle anderen nur lesen \tabularnewline\STRUT
u=rwx,go=rx & 755 & Der Besitzer darf lesen, schreiben und ausführen, alle anderen nur lesen und ausführen
\end{longtable}

View File

@ -0,0 +1,16 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\textsl{s=\dq{}Dies ist ein Test\dq{}} & ~ \tabularnewline\STRUT
\texttt{echo \dq{}\$s\dq{} | cut -c 2-6} & gibt `ies i' aus \tabularnewline\STRUT
\texttt{echo \dq{}\$s\dq{} | cut -d \dq{}~\dq{} -f 2} & gibt `ist' aus \tabularnewline\STRUT
\texttt{echo \dq{}\$s\dq{} | cut -d \dq{}~\dq{} -f 2-3} & gibt `ist ein' aus \tabularnewline\STRUT
\texttt{echo \dq{}\$s\dq{} | cut -d \dq{}~\dq{} -f 2-} & gibt `ist ein Test' aus
\end{longtable}

View File

@ -0,0 +1,16 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-n} & Unterdrückt den Zeilenumbruch am Ende der Ausgabe \tabularnewline\STRUT
\texttt{-e} & Aktiviert die Interpretation von Steuerzeichen. Diese
Steuerzeichen werden mit einem Backslash gequoted, der ganze String muß in
Ticks eingeschlossen werden. Beispielsweise gibt \texttt{echo -e
'hallo\textbackslash a'} das Wort hallo und einen Piepton aus.
\end{longtable}

View File

@ -0,0 +1,19 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{foo=42} & Der Variablen namens `foo' wird der Wert `42' zugewiesen. \tabularnewline\STRUT
\texttt{a=foo} & Der Variablen namens `a' wird der Wert `foo' zugewiesen. \tabularnewline\STRUT
\texttt{b='\$'\$a} & Der Variablen `b' wird ein \$ und der Inhalt der Variablen namens `a' zugewiesen. \tabularnewline\STRUT
\texttt{echo \$b} & Der Inhalt der Variablen `b' wird ausgegeben. \tabularnewline\STRUT
\textsl{\$foo} & \tabularnewline\STRUT
\texttt{eval b='\$'\$a} & Zunächst wird die Zeile nach dem \texttt{eval} expandiert, Variablen werden durch Inhalte ersetzt. Es entsteht also ein neuer Ausdruck: `b=\$foo'. Der wird dann von \texttt{eval} ausgeführt. \tabularnewline\STRUT
\texttt{echo \$b} & Der neue Inhalt der Variablen `b' wird ausgegeben. \tabularnewline\STRUT
\textsl{42} &
\end{longtable}

View File

@ -0,0 +1,29 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{|} & logisches `oder' \tabularnewline\STRUT
\texttt{\&} & logisches `und' \tabularnewline\STRUT
\texttt{<} & kleiner als \tabularnewline\STRUT
\texttt{<=} & kleiner als oder gleich \tabularnewline\STRUT
\texttt{=} & gleich \tabularnewline\STRUT
\texttt{!=} & ungleich \tabularnewline\STRUT
\texttt{>=} & größer als oder gleich \tabularnewline\STRUT
\texttt{>} & größer als \tabularnewline\STRUT
\texttt{+} & Addition \tabularnewline\STRUT
\texttt{-} & Subtraktion \tabularnewline\STRUT
\texttt{*} & Multiplikation \tabularnewline\STRUT
\texttt{/} & Division \tabularnewline\STRUT
\texttt{\%} & Modulo (`Divisionsrest') \tabularnewline\STRUT
\texttt{:} & Pattern-Match mit regulären Ausdrücken \tabularnewline\STRUT
\texttt{match} & Analog zu `:' \tabularnewline\STRUT
\texttt{substr} & Teil einer Zeichenkette zurückgeben \tabularnewline\STRUT
\texttt{index} & Position einer Zeichenkette in einer anderen finden \tabularnewline\STRUT
\texttt{length} & Länge einer Zeichenkette
\end{longtable}

View File

@ -0,0 +1,31 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
Kriterien: & \tabularnewline\STRUT
\texttt{-name }\textsl{pattern} & Suchmuster für den Dateinamen, auch mit Meta-Zeichen (Abschnitt \ref{metazeichen}) \tabularnewline\STRUT
\texttt{-perm [-]}\textsl{mode} & Sucht nach Dateien, deren Berechtigungen dem angegebenen Modus entsprechen. Die Notation erfolgt dabei analog zu \texttt{chmod} (Abschnitt \ref{chmod}), wahlweise in der Buchstaben- oder in der Zahlenform \tabularnewline\STRUT
\texttt{-type }\textsl{c} & Sucht nach Dateien des angegebenen Typs. Dabei kann für \textsl{c} `b' (block device), `c' (character device), `d' (directory), `l' (symbolic link), `p' (pipe), `f' (regular file), oder `s' (socket) eingesetzt werden \tabularnewline\STRUT
\texttt{-user }\textsl{name} & Sucht nach Dateien, die dem angegebenen Benutzer gehören. Die Angabe kann als Name oder als UID erfolgen \tabularnewline\STRUT
\texttt{-group }\textsl{name} & Sucht nach Dateien, die der angegebenen Gruppe gehören. Die Angabe kann als Name oder als GID erfolgen \tabularnewline\STRUT
\texttt{-size }\textsl{n}\texttt{[c]} & Sucht nach Dateien, deren Größe \textsl{n} Blocks\footnote{Blocks geben die Dateigröße in Bytes dividiert durch 512 und aufgerundet auf den nächsten Integer an. Das hat historische Gründe.} oder bei nachgestelltem \texttt{c} \textsl{n} Bytes ist \tabularnewline\STRUT
\texttt{-atime }\textsl{n} & Sucht nach Dateien, deren letzter Zugriff (access time) \texttt{n}*24 Stunden zurück liegt \tabularnewline\STRUT
\texttt{-ctime }\textsl{n} & Sucht nach Dateien, deren letzte Statusänderung (change time) \texttt{n}*24 Stunden zurück liegt \tabularnewline\STRUT
\texttt{-mtime }\textsl{n} & Sucht nach Dateien, deren letzte Änderung (modification time) \texttt{n}*24 Stunden zurück liegt \tabularnewline\STRUT
\texttt{-newer }\textsl{file} & Sucht nach Dateien, die jünger sind als \textsl{file} \tabularnewline\STRUT
Optionen: & \tabularnewline\STRUT
\texttt{-xdev} & Nur auf einem Filesystem suchen \tabularnewline\STRUT
\texttt{-depth } & Normalerweise wird eine Breitensuche durchgeführt, dieser Parameter schaltet auf Tiefensuche um \tabularnewline\STRUT
Aktionen: & \tabularnewline\STRUT
\texttt{-print} & Dies ist default, die gefundenen Dateinamen werden ausgegeben \tabularnewline\STRUT
\texttt{-exec }\textsl{kommando}\texttt{ \{\};} & Führt das Kommando für jede
Fundstelle aus, an Stelle der geschweiften Klammern wird der gefundene
Dateiname eingesetzt. Das abschließende Semikolon muß wegen seiner
Sonderbedeutung in der Regel durch einen Backslash gequoted werden
\end{longtable}

View File

@ -0,0 +1,20 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-E} & Benutzt erweiterte reguläre Ausdrücke \tabularnewline\STRUT
\texttt{-F} & Der Suchbegriff wird nicht als regulärer Ausdruck, sondern als `fixed String' benutzt \tabularnewline\STRUT
\texttt{-c} & Gibt für jede durchsuchte Datei die Anzahl der Fundstellen aus \tabularnewline\STRUT
\texttt{-f} & Liest die Suchbegriffe Zeile für Zeile aus einer Textdatei \tabularnewline\STRUT
\texttt{-i} & Ignoriert die Unterscheidung zwischen Groß- und Kleinschreibung \tabularnewline\STRUT
\texttt{-l} & Gibt nur die Dateinamen aus \tabularnewline\STRUT
\texttt{-n} & Gibt zusätzlich die Zeilennummern der Fundstellen aus \tabularnewline\STRUT
\texttt{-q} & Gibt die Fundstellen nicht aus, am Exitcode ist zu erkennen ob etwas gefunden wurde \tabularnewline\STRUT
\texttt{-v} & Findet alle Zeilen, in denen das Suchmuster \emph{nicht} vorkommt
\end{longtable}

View File

@ -0,0 +1,23 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-1} & Formatiert die Ausgabe einspaltig \tabularnewline\STRUT
\texttt{-a} & Zeigt alle Dateien an, auch solche deren Name mit einem Punkt anfängt \tabularnewline\STRUT
\texttt{-A} & \ding{43} Zeigt `fast alle' Dateien an, also auch alle deren Name mit einem Punkt anfängt, allerdings nicht `.' und `..', die in jedem Verzeichnis vorkommen \tabularnewline\STRUT
\texttt{-d} & Verzeichnisse werden behandelt wie jede andere Datei auch, ein \texttt{ls -ld verzeichnis} gibt also die Eigenschaften des Verzeichnisses aus, nicht dessen Inhalt \tabularnewline\STRUT
\texttt{-h} & \ding{43} Gibt bei einer langen Ausgabe mittels \texttt{-l} die Größe der Datei `human readable' aus, also nicht zwingend in Bytes \tabularnewline\STRUT
\texttt{-l} & Lange Ausgabe, inklusiv der Dateiattribute \tabularnewline\STRUT
\texttt{-L} & \ding{43} `Dereferenziert' Links vor der Ausgabe. Es werden nicht die Eigenschaften des Links angezeigt, sondern die der verlinkten Datei \tabularnewline\STRUT
\texttt{-r} & Sortierreihenfolge umkehren \tabularnewline\STRUT
\texttt{-R} & Rekursiv in Verzeichnisse absteigen und deren Inhalte anzeigen \tabularnewline\STRUT
\texttt{-S} & \ding{43} Nach der Größe der Datei sortieren \tabularnewline\STRUT
\texttt{-t} & Nach der letzten Änderungszeit sortieren \tabularnewline\STRUT
\texttt{-X} & \ding{43} Nach der Extension (also dem Namensteil nach dem letzten Punkt) sortieren
\end{longtable}

View File

@ -0,0 +1,15 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-f} & Normalerweise wird nur nach Prozeß-Namen gesucht, mit diesem Parameter wird das volle Kommando (incl. Pfad und Parametern) betrachtet\tabularnewline\STRUT
\texttt{-l} & Nicht nur die Prozeß-ID, sondern das volle Kommando wird ausgegeben\tabularnewline\STRUT
\texttt{-v} & Findet alle Zeilen, in denen das Suchmuster \emph{nicht} vorkommt\tabularnewline\STRUT
\texttt{-x} & Sucht nach Kommandos, deren Name dem Muster \emph{exakt} entspricht
\end{longtable}

View File

@ -0,0 +1,15 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{\%b} & Behandelt die Ausgabe von Backslash-Sequenzen. Die Sequenzen sind im Abschnitt über \texttt{echo} (\ref{echo}) beschrieben. \tabularnewline\STRUT
\texttt{\%s} & Gibt den nächsten Datenstring aus \tabularnewline\STRUT
\texttt{\%}\textsl{n}\texttt{\$s} & Gibt den \textsl{n}-ten Datenstring aus \tabularnewline\STRUT
\texttt{\%[-]}\textsl{m}\texttt{[.}\textsl{n}\texttt{]s} & Gibt den nächsten String aus, dazu wird ein Platz von \textsl{m} Zeichen reserviert. Optional können nur die ersten \textsl{n} Zeichen ausgegeben oder mit \texttt{-} eine Rechtsbündige Formatierung festgelegt werden.
\end{longtable}

View File

@ -0,0 +1,19 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{d} & Keine Adresse angegeben, alle Zeilen werden gelöscht \tabularnewline\STRUT
\texttt{23d} & Zeile 23 wird gelöscht \tabularnewline\STRUT
\texttt{\$d} & Die letzte Eingabezeile wird gelöscht \tabularnewline\STRUT
\texttt{/}\textsl{pattern}\texttt{/d} & Jede Zeile, die den regulären Ausdruck \textsl{pattern} enthält wird gelöscht \tabularnewline\STRUT
\texttt{23,42d} & Die Zeilen 23 bis einschließlich 42 werden gelöscht \tabularnewline\STRUT
\texttt{23,\$d} & Von Zeile 23 bis zum Ende wird gelöscht \tabularnewline\STRUT
\texttt{1,/\^\$/d} & Von der ersten bis zur ersten Leerzeile wird gelöscht \tabularnewline\STRUT
\texttt{23,42!d} & Alles außer den Zeilen 23 bis 42 wird gelöscht
\end{longtable}

View File

@ -0,0 +1,17 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
Editieren: & \tabularnewline\STRUT
\texttt{/}\textsl{adresse}\texttt{/d} & Zeilen löschen \tabularnewline\STRUT
\texttt{s/}\textsl{regexp1}\texttt{/}\textsl{regexp2}\texttt{/} & Substitution: Suchen und ersetzen \tabularnewline\STRUT
\texttt{y/}\textsl{menge1}\texttt{/}\textsl{menge2}\texttt{/} & Zeichen ersetzen \tabularnewline\STRUT
Zeileninformation: & \tabularnewline\STRUT
\texttt{/}\textsl{adresse}\texttt{/p} & Zeilen ausgeben
\end{longtable}

View File

@ -0,0 +1,16 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-k 3} & Sortiert nach dem dritten Feld \tabularnewline\STRUT
\texttt{-k 3.5} & Sortiert nach dem fünften Zeichen des dritten Feldes \tabularnewline\STRUT
\texttt{-k 3.5r} & Sortiert rückwärts nach dem fünften Zeichen des dritten Feldes \tabularnewline\STRUT
\texttt{-k 3,5} & Beachtet bei der Sortierung nur das dritte bis fünfte Feld \tabularnewline\STRUT
\texttt{-k 3.5,3.8} & Beachtet die Zeichen fünf bis acht des dritten Feldes
\end{longtable}

View File

@ -0,0 +1,20 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-b} & Ignoriert führende Leerzeichen \tabularnewline\STRUT
\texttt{-c} & Prüft nur, ob die Eingabedaten bereits sortiert sind \tabularnewline\STRUT
\texttt{-f} & Groß- / Kleinschreibung nicht beachten \tabularnewline\STRUT
\texttt{-i} & Nur `printable' Zeichen beachten \tabularnewline\STRUT
\texttt{-k} & Sortiert nicht nach der ersten, sondern nach der angegebenen Spalte (siehe unten) \tabularnewline\STRUT
\texttt{-n} & Numerische Sortierung \tabularnewline\STRUT
\texttt{-r} & Sortierreihenfolge umkehren \tabularnewline\STRUT
\texttt{-t} & Normalerweise fängt ein Feld (siehe \texttt{-k}) beim Übergang von `blank' nach `non-blank' an, mit diesem Parameter können ander Feld-Trenner definiert werden \tabularnewline\STRUT
\texttt{-u} & Gibt bei identischen Zeilen nur die erste Fundstelle aus (unique)
\end{longtable}

View File

@ -0,0 +1,19 @@
% $Id$
\begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\texttt{-c} & Anzahl der Vorkommnisse vor die Zeilen schreiben \tabularnewline\STRUT
\texttt{-d} & Nur doppelte Zeilen ausgeben, jede nur einmal \tabularnewline\STRUT
\texttt{-D} & \ding{43} Alle doppelten Zeilen ausgeben \tabularnewline\STRUT
\texttt{-f }\textsl{n} & Die ersten \textsl{n} Felder ignorieren \tabularnewline\STRUT
\texttt{-i} & \ding{43} Groß- / Kleinschreibung ignorieren \tabularnewline\STRUT
\texttt{-s }\textsl{n} & Die ersten \textsl{n} Zeichen ignorieren \tabularnewline\STRUT
\texttt{-u} & Nur einfach vorkommende Zeilen ausgeben \tabularnewline\STRUT
\texttt{-w }\textsl{n} & \ding{43} Nur die ersten \textsl{n} Zeichen betrachten
\end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|c|c|c|X|} \begin{longtable}{|l|c|c|c|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|c|c|c|c|c|c|c|X|} \begin{longtable}{|l|c|c|c|c|c|c|c|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -9,11 +10,12 @@
\texttt{;} & Befehls-Trennzeichen\index{Befehls>-Trennzeichen} \tabularnewline\STRUT \texttt{;} & Befehls-Trennzeichen\index{Befehls>-Trennzeichen} \tabularnewline\STRUT
\texttt{\&} & Hintergrund-Verarbeitung \tabularnewline\STRUT \texttt{\&} & Hintergrund-Verarbeitung \tabularnewline\STRUT
\texttt{( )} & Befehlsfolge\index{Befehls>-folge} \tabularnewline\STRUT \texttt{( ) \{ \}} & Befehlsfolge\index{Befehls>-folge} \tabularnewline\STRUT
\texttt{|} & Pipe \tabularnewline\STRUT \texttt{|} & Pipe \tabularnewline\STRUT
\texttt{< > >\&} & Umlenkungssymbole \tabularnewline\STRUT \texttt{< > >\&} & Umlenkungssymbole \tabularnewline\STRUT
\texttt{* ? [ ] \~{} + - @ !} & Meta-Zeichen\index{Meta-Zeichen} für Dateinamen \tabularnewline\STRUT \texttt{* ? [ ] \~{} + - @ !} & Meta-Zeichen\index{Meta-Zeichen} für Dateinamen \tabularnewline\STRUT
\texttt{` ` }(Backticks\footnote{Man erhält sie durch \Ovalbox{SHIFT} und die Taste neben dem Backspace.}) & Befehls-Substitution\index{Befehls>-Substitution} \tabularnewline\STRUT \texttt{` ` }(Backticks oder Single Backquotes\footnote{Man erhält sie üblicherweise durch \Ovalbox{SHIFT} und die Taste neben dem Backspace.}) & Befehls-Substitution\index{Befehls>-Substitution} \tabularnewline\STRUT
\texttt{\$} & Variablen-Substitution\index{Variablen>-Substitution} \tabularnewline\STRUT \texttt{\$} & Variablen-Substitution\index{Variablen>-Substitution} \tabularnewline\STRUT
\texttt{\Ovalbox{NEWLINE} \Ovalbox{SPACE} \Ovalbox{TAB}} & Wort-Trennzeichen\footnote{Die Wort-Trennzeichen sind in der Variable \texttt{\$IFS}\index{\$IFS=\texttt{\$IFS}} abgelegt. Man kann diese Variable auch überschreiben, um elegant Strings zu zerlegen.} \texttt{\Ovalbox{NEWLINE} \Ovalbox{SPACE} \Ovalbox{TAB}} &
Wort-Trennzeichen\footnote{Die Wort-Trennzeichen sind in der vordefinierten Variable \texttt{\$IFS} abgelegt. Siehe Abschnitt \ref{vordefinierte_variablen}.}
\end{longtable} \end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -7,17 +8,18 @@
\hline \hline
\endlastfoot \endlastfoot
\texttt{\dq~\dq} & (Anführungszeichen) Alles zwischen diesen Zeichen ist \texttt{\dq~\dq} & (Anführungszeichen oder Double Quotes) Alles zwischen diesen
buchstabengetreu zu interpretieren. Ausnahmen sind folgende Zeichen, die ihre Zeichen ist buchstabengetreu zu interpretieren. Ausnahmen sind folgende
spezielle Bedeutung beibehalten: \texttt{\$ ` \dq} \tabularnewline\STRUT Zeichen, die ihre spezielle Bedeutung beibehalten: \texttt{\$ ` \dq}
\texttt{' '} & (Ticks\footnote{Sie liegen auf der Tastatur über der Raute.})
Alls zwischen diesen Zeichen wird wörtlich genommen, mit Ausnahme eines
weiteren \texttt{'} oder eines Backslashes (\texttt{\textbackslash})
\tabularnewline\STRUT \tabularnewline\STRUT
\texttt{' '} & (Ticks oder (Single) Quotes\footnote{Sie liegen auf der Tastatur
über der Raute.}) Alls zwischen diesen Zeichen wird wörtlich genommen, mit
Ausnahme eines weiteren \texttt{'} oder eines Backslashes
(\texttt{\textbackslash}) \tabularnewline\STRUT
\texttt{\textbackslash} & (Backslash\index{Backslash}) Das Zeichen nach einem \texttt{\textbackslash} & (Backslash\index{Backslash}) Das Zeichen nach einem
\textbackslash wird wörtlich genommen. Anwendung z. B. innerhalb von \textbackslash wird wörtlich genommen. Anwendung z.~B. innerhalb von
\texttt{\dq~\dq}, um \texttt{\dq}, \texttt{\$} und \texttt{`} zu entwerten. \texttt{\dq~\dq}, um \texttt{\dq}, \texttt{\$} und \texttt{`} zu entwerten.
Häufig verwendet zur Angabe von Leerzeichen (space) und Zeilenendezeichen, oder Häufig verwendet zur Angabe von Leerzeichen (space) und Zeilenendezeichen, oder
um ein \textbackslash -Zeichen selbst anzugeben. um ein \textbackslash -Zeichen selbst anzugeben.

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|l|X|} \begin{longtable}{|l|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -11,6 +12,6 @@ Nummer & Name & Bedeutung \\
0 & Normal Exit & Wird durch das \texttt{exit}\index{exit=\texttt{exit}}-Kommando ausgelöst. \tabularnewline\STRUT 0 & Normal Exit & Wird durch das \texttt{exit}\index{exit=\texttt{exit}}-Kommando ausgelöst. \tabularnewline\STRUT
1 & SIGHUP & Wenn die Verbindung abbricht (z. B. wenn das Terminal geschlossen wird). \tabularnewline\STRUT 1 & SIGHUP & Wenn die Verbindung abbricht (z. B. wenn das Terminal geschlossen wird). \tabularnewline\STRUT
2 & SIGINT & Zeigt einen Interrupt an (\Ovalbox{CTRL}-\Ovalbox{C}). \tabularnewline\STRUT 2 & SIGINT & Zeigt einen Interrupt an (\Ovalbox{CTRL}+\Ovalbox{C}). \tabularnewline\STRUT
15 & SIGTERM & Wird vom \texttt{kill}\index{kill=\texttt{kill}}-Kommando gesendet. 15 & SIGTERM & Wird vom \texttt{kill}\index{kill=\texttt{kill}}-Kommando gesendet.
\end{longtable} \end{longtable}

View File

@ -1,14 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{until }\textsl{Bedingung}} \\
\multicolumn{2}{|X|}{\texttt{do}} \\
\multicolumn{2}{|X|}{\texttt{~}\textsl{Befehle}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -8,9 +9,9 @@
\endlastfoot \endlastfoot
\textsl{Variable}\texttt{=}\textsl{Wert} & Setzt die \textsl{Variable} auf den \textsl{Wert}. Dabei ist unbedingt darauf zu achten, daß zwischen dem Variablennamen und dem Gleichheitszeichen keine Leerzeichen stehen. \tabularnewline\STRUT \textsl{Variable}\texttt{=}\textsl{Wert} & Setzt die \textsl{Variable} auf den \textsl{Wert}. Dabei ist unbedingt darauf zu achten, daß zwischen dem Variablennamen und dem Gleichheitszeichen keine Leerzeichen stehen. \tabularnewline\STRUT
\texttt{\$\{}\textsl{Variable}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Die Klammern müssen nicht mit angegeben werden, wenn die \textsl{Variable} von Trennzeichen umgeben ist. \tabularnewline\STRUT \texttt{\$\{}\textsl{Variable}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Die Klammern müssen nur angegeben werden, wenn auf die \textsl{Variable} eine Zahl, ein Buchstabe oder ein Unterstrich folgen. \tabularnewline\STRUT
\texttt{\$\{}\textsl{Variable}\texttt{:-}\textsl{Wert}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Falls die \textsl{Variable} nicht gesetzt ist, wird der \textsl{Wert} benutzt. \tabularnewline\STRUT \texttt{\$\{}\textsl{Variable}\texttt{:-}\textsl{Wert}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Falls die \textsl{Variable} nicht gesetzt oder leer ist, wird \textsl{Wert} benutzt. \tabularnewline\STRUT
\texttt{\$\{}\textsl{Variable}\texttt{:=}\textsl{Wert}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Falls die \textsl{Variable} nicht gesetzt ist, wird der \textsl{Wert} benutzt, und \textsl{Variable} erhält den \textsl{Wert}. \tabularnewline\STRUT \texttt{\$\{}\textsl{Variable}\texttt{:=}\textsl{Wert}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Falls die \textsl{Variable} nicht gesetzt oder leer ist, wird \textsl{Wert} benutzt, und \textsl{Variable} erhält den \textsl{Wert}. \tabularnewline\STRUT
\texttt{\$\{}\textsl{Variable}\texttt{:?}\textsl{Wert}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Falls die \textsl{Variable} nicht gesetzt ist, wird der \textsl{Wert} ausgegeben und die Shell beendet. Wenn kein \textsl{Wert} angegeben wurde, wird der Text \texttt{parameter null or not set} ausgegeben. \tabularnewline\STRUT \texttt{\$\{}\textsl{Variable}\texttt{:?}\textsl{Wert}\texttt{\}} & Nutzt den Wert von \textsl{Variable}. Falls die \textsl{Variable} nicht gesetzt oder leer ist, wird der \textsl{Wert} ausgegeben und die Shell beendet. Wenn kein \textsl{Wert} angegeben wurde, wird der Text \texttt{parameter null or not set} ausgegeben. \tabularnewline\STRUT
\texttt{\$\{}\textsl{Variable}\texttt{:+}\textsl{Wert}\texttt{\}} & Nutzt den \textsl{Wert}, falls die \textsl{Variable} gesetzt ist, andernfalls nichts. \texttt{\$\{}\textsl{Variable}\texttt{:+}\textsl{Wert}\texttt{\}} & \textsl{Wert}, falls die \textsl{Variable} gesetzt und nicht leer ist, andernfalls nichts.
\end{longtable} \end{longtable}

View File

@ -1,3 +1,4 @@
% $Id$
\begin{longtable}{|l|X|} \begin{longtable}{|l|X|}
% KILLED & LINE!!!! \kill % KILLED & LINE!!!! \kill
\hline \hline
@ -15,6 +16,8 @@
\texttt{\$\$} & Prozeßnummer der aktiven Shell \tabularnewline\STRUT \texttt{\$\$} & Prozeßnummer der aktiven Shell \tabularnewline\STRUT
\texttt{\$!} & Prozeßnummer des letzten Hintergrundprozesses \tabularnewline\STRUT \texttt{\$!} & Prozeßnummer des letzten Hintergrundprozesses \tabularnewline\STRUT
\texttt{\$ERRNO} & Fehlernummer des letzten fehlgeschlagenen Systemaufrufs \tabularnewline\STRUT \texttt{\$ERRNO} & Fehlernummer des letzten fehlgeschlagenen Systemaufrufs \tabularnewline\STRUT
\texttt{\$PWD} & Aktuelles Verzeichnis (wird durch \texttt{cd} gesetzt\footnote{Durch das Kommando \texttt{cd} wird das aktuelle Verzeichnis gewechselt.}) \tabularnewline\STRUT \texttt{\$IFS} & Feldseparator, wird beispielsweise beim Lesen mittels \texttt{read} benutzt \tabularnewline\STRUT
\texttt{\$PATH} & Pfad, in dem nach ausführbaren Kommandos gesucht wird\footnote{Mit dem Kommando \texttt{type}\index{type=\texttt{type}} findet man heraus, welches Executable tatsächlich verwendet wird.}. Mehrere Einträge werden durch Doppelpunkte getrennt angegeben \tabularnewline\STRUT
\texttt{\$PWD} & Aktuelles Verzeichnis (wird durch \texttt{cd} gesetzt\footnote{Durch das Kommando \texttt{cd} wird das aktuelle Verzeichnis gewechselt, siehe Abschnitt \ref{cd}.}) \tabularnewline\STRUT
\texttt{\$OLDPWD} & Vorheriges Verzeichnis (wird durch \texttt{cd} gesetzt) \texttt{\$OLDPWD} & Vorheriges Verzeichnis (wird durch \texttt{cd} gesetzt)
\end{longtable} \end{longtable}

View File

@ -1,14 +0,0 @@
\begin{longtable}{|X l|}
% KILLED & LINE!!!! \kill
\hline
\endfirsthead
\endhead
\endfoot
\hline
\endlastfoot
\multicolumn{2}{|X|}{\texttt{while }\textsl{Bedingung}} \\
\multicolumn{2}{|X|}{\texttt{do}} \\
\multicolumn{2}{|X|}{\texttt{~}\textsl{Befehle}} \\
\multicolumn{2}{|X|}{\texttt{done}} \\
\end{longtable}

29
todo.tex Normal file
View File

@ -0,0 +1,29 @@
% $Id$
\chapter{Routenplanung - Die Zukunft dieses Dokuments}
Ich werde in dieser Version des Dokumentes nicht alles umgesetzt haben, was mir
sinnvoll erscheint. An dieser Stelle sammele ich Ideen für eine nächste
Version. Kommentare dazu nehme ich jederzeit dankend entgegen.
\begin{itemize}
\item \textbf{GNU / Posix:} Bessere Abgrenzung der GNU-Erweiterungen
ge\-gen\-ü\-ber dem Posix-Standard, damit die Skripte portabel bleiben und
nicht nur auf Linux laufen.
\item \textbf{Performance:} Ein Kapitel mit Hinweisen, wie Skripte nicht
unnötig langsam werden.
\item \textbf{Interaktive Shell:} Exkurs zur interaktiven Benutzung der Bash.
Es gibt da eine Reihe hilfreicher Tastenkombinationen, die längst nicht jedem
bekannt sind.
\item \textbf{HTML-Version:} Ich würde gerne eine HTML-Version zur Verfügung
stellen, bin mir aber noch nicht sicher ob das aus den \LaTeX-Quellen geht. Mir
liegt dabei die Indizierung der Stichworte am Herzen, die sollte nicht
verloren gehen.
\item \textbf{Glossar:} Verzeichnis von Begriffen wie PID, Prompt, GID, UID,
Cron, usw.
\end{itemize}

View File

@ -1,45 +1,126 @@
% $Id$
\chapter{Was ist die Shell?}\index{Shell} \chapter{Was ist die Shell?}\index{Shell}
Die Shell ist ein Programm, mit dessen Hilfe das System die Benutzerbefehle verstehen kann. Aus diesem Grund wird die Shell auch oft als Befehls- oder Kommandointerpreter bezeichnet. Die Shell ist ein Programm, mit dessen Hilfe das System die Benutzerbefehle
verstehen kann. Aus diesem Grund wird die Shell auch oft als Befehls- oder
Kommandointerpreter bezeichnet.
\section{Sinn und Zweck} \section{Sinn und Zweck}
In einem klassischen Unix-System (ohne die grafische Oberfläche X) greifen die Benutzer über Terminals\index{Terminal} auf das System zu. Auf diesen Terminals können nur Textzeichen dargestellt werden. Um dem Benutzer die Arbeit mit dem System effektiv möglich zu machen, gibt es die Shell. Die Shell wird dabei für drei Hauptaufgaben benutzt: In einem klassischen Unix-System (ohne die grafische Oberfläche X) greifen die
Benutzer über Terminals\index{Terminal} auf das System zu. Auf diesen Terminals
können nur Textzeichen dargestellt werden. Um dem Benutzer die Arbeit mit dem
System effektiv möglich zu machen, gibt es die Shell. Die Shell wird dabei für
drei Hauptaufgaben benutzt:
\begin{itemize} \begin{itemize}
\item Interaktive Anwendung (Dialog) \item Interaktive Anwendung (Dialog)
\item Anwendungsspezifische Anpassung des Unix-Systemverhaltens (Belegen von Umgebungsvariablen) \item Anwendungsspezifische Anpassung des Unix-Systemverhaltens (Belegen von Umgebungsvariablen)
\item Programmierung (Shell-Skripting). Zu diesem Zweck stehen einige Mechanismen zur Verfügung, die aus Hochsprachen bekannt sind (Variablen, Datenströme, Funktionen usw.). \item Programmierung (Shell-Skripting). Zu diesem Zweck stehen einige Mechanismen zur Verfügung, die aus Hochsprachen bekannt sind (Variablen, Datenströme, Funktionen usw.).
\end{itemize} \end{itemize}
Ursprünglich handelte es sich dabei um ein relativ einfaches Programm, der Bourne Shell (wird oft auch Standard-Shell genannt). Dies ist praktisch die "`Mutter aller Shells"'. Aus dieser entwickelten sich im Laufe der Zeit mehrere Varianten, die alle ihre eigenen Vor- und Nachteile mit sich bringen. Da es unter Unix kein Problem darstellt den Kommandointerpreter auszutauschen, stehen auf den meisten Systemen mehrere dieser Shells zur Verfügung. Welche Variante ein Benutzer verwenden möchte ist reine Geschmackssache. Ursprünglich handelte es sich dabei um ein relativ einfaches Programm, der
Bourne Shell (wird oft auch Standard-Shell genannt). Dies ist praktisch die
"`Mutter aller Shells"'. Aus dieser entwickelten sich im Laufe der Zeit mehrere
Varianten, die alle ihre eigenen Vor- und Nachteile mit sich bringen. Da es
unter Unix kein Problem darstellt den Kommandointerpreter auszutauschen, stehen
auf den meisten Systemen mehrere dieser Shells zur Verfügung. Welche Variante
ein Benutzer verwenden möchte ist reine Geschmackssache.
\section{Die Qual der Wahl} \section{Die Qual der Wahl}
Um die Auswahl einer Shell zu erleichtern, werden hier die wichtigsten Varianten kurz vorgestellt. Sie sind aufgeteilt in Einfach- und Komfort-Shells. Die Komfort-Shells zeichnen sich durch komfortablere Funktionen zur interaktiven Bedienung aus, während die Einfach-Versionen üblicherweise für die Programmierung benutzt werden. Um die Auswahl einer Shell zu erleichtern, werden hier die wichtigsten
Varianten kurz vorgestellt. Sie sind aufgeteilt in Einfach- und Komfort-Shells.
Die Komfort-Shells zeichnen sich durch komfortablere Funktionen zur
interaktiven Bedienung aus, während die Einfach-Versionen üblicherweise für die
Programmierung benutzt werden.
\medskip\emph{Einfach-Shells:}\nopagebreak \medskip\emph{Einfach-Shells:}\nopagebreak
\begin{itemize} \begin{itemize}
\item Die Bourne-\index{Bourne-Shell|textbf}\index{Shell>Bourne-|see{Bourne-Shell}} oder Standard-Shell\index{Shell>Standard-|see{Bourne-Shell}}\index{Standard-Shell|see{Bourne-Shell}} (\texttt{sh}\index{sh=\texttt{sh}|see{Bourne-Shell}}) ist die kompakteste und einfachste Form. Sie bietet schon Mechanismen wie die Umlenkung der Ein- oder Ausgaben, Wildcards zur Abkürzung von Dateinamen, Shell-Variablen und einen Satz interner Befehle zum Schreiben von Shell-Prozeduren. Neuere Versionen beherrschen auch das Job-Controlling\index{Job-Controlling}. Für die Entwicklung von Shell-Skripten sollte man sich auf diese Shell beschränken, da sie auf praktisch allen Systemen zur Verfügung steht. So bleiben die Skripte portabel. \item Die
Bourne-\index{Bourne-Shell|textbf}\index{Shell>Bourne-|see{Bourne-Shell}} oder
Standard-Shell\index{Shell>Standard-|see{Bourne-Shell}}\index{Standard-Shell|see{Bourne-Shell}}
(\texttt{sh}\index{sh=\texttt{sh}|see{Bourne-Shell}}) ist die kompakteste und
einfachste Form. Sie bietet schon Mechanismen wie die Umlenkung der Ein- oder
Ausgaben, Wildcards zur Abkürzung von Dateinamen, Shell-Variablen und einen
Satz interner Befehle zum Schreiben von Shell-Prozeduren. Neuere Versionen
beherrschen auch das Job-Controlling\index{Job-Controlling}.
\item Die Korn-Shell\index{Korn-Shell|textbf}\index{Shell>Korn-|see{Korn-Shell}} (\texttt{ksh}\index{ksh=\texttt{ksh}|see{Korn-Shell}}), eine Weiterentwicklung der Bourne-Shell, erlaubt das editieren in der Befehlszeile. Außerdem gibt es hier History\index{History}-Funktionen\footnote{History-Funktionen ermöglichen es dem Benutzer, einfach auf zurückliegende Befehle zurückgreifen zu können.}, eine Ganzzahl-Arithmetik, verbesserte Möglichkeiten zur Mustererkennung, Aliase\index{Aliase}\footnote{Ein Alias ist eine Abkürzung für einen Befehl. Beispielsweise kann man das Häufig benutzte \texttt{ls -la} einfach durch \texttt{la} ersetzen.} und das Job-Controlling\footnote{Unter Job-Controlling versteht man einen Mechanismus, mit dessen Hilfe der Benutzer die Ausführung von Prozessen selektiv stoppen oder fortsetzen kann}\index{Job-Controlling}. Außerdem bietet die Korn-Shell im Gegensatz zu fast allen anderen Shells die Möglichkeit, Aliase und Shell-Funktionen an Subshells zu vererben. Für die Entwicklung von Shell-Skripten sollte man sich auf diese Shell
beschränken, da sie auf praktisch allen Systemen zur Verfügung steht. So
bleiben die Skripte mit kleinen Einschränkungen\footnote{Die verschiedenen
Implementierungen weisen kleine Unterschiede, z. B. bei der Behandlung von \$@
oder den Parametern von \texttt{read} (-r) auf.} portabel.
\item Die C-Shell \index{C-Shell|textbf}\index{Shell>C-|see{C-Shell}} (\texttt{csh}\index{csh=\texttt{csh}|see{C-Shell}}) bietet ähnliche Annehmlichkeiten wie die Korn-Shell, lehnt sich aber in der Syntax sehr stark an die Programmiersprache C an. Sie sollte nach Möglichkeit nicht zur Shell-Programmierung benutzt werden, da sie an vielen Stellen nicht so reagiert, wie man es erwarten sollte. \item Die
Korn-Shell\index{Korn-Shell|textbf}\index{Shell>Korn-|see{Korn-Shell}}
(\texttt{ksh}\index{ksh=\texttt{ksh}|see{Korn-Shell}}), eine Weiterentwicklung
der Bourne-Shell, erlaubt das Editieren in der Befehlszeile. Außerdem gibt es
hier History\index{History}-Funktionen\footnote{History-Funktionen ermöglichen
es dem Benutzer, einfach auf zurückliegende Befehle zurückgreifen zu können.},
eine Ganzzahl-Arithmetik, verbesserte Möglichkeiten zur Mustererkennung,
Arrays, Aliase\index{Aliase}\footnote{Ein Alias ist eine Abkürzung für einen
Befehl. Beispielsweise kann man das Häufig benutzte \texttt{ls -la} einfach
durch \texttt{la} ersetzen.} und das Job-Controlling\footnote{Unter
Job-Controlling versteht man einen Mechanismus, mit dessen Hilfe der Benutzer
die Ausführung von Prozessen selektiv stoppen oder fortsetzen
kann}\index{Job-Controlling}. Außerdem bietet die Korn-Shell im Gegensatz zu
fast allen anderen Shells die Möglichkeit, Aliase und Shell-Funktionen an
Subshells zu vererben.
Die Korn-Shell existiert in verschiedenen Implementierungen, sowohl kommerziell
(ksh88), kostenlos (ksh93) als auch frei (pdksh).
\item Die C-Shell \index{C-Shell|textbf}\index{Shell>C-|see{C-Shell}}
(\texttt{csh}\index{csh=\texttt{csh}|see{C-Shell}}) bietet ähnliche
Annehmlichkeiten wie die Korn-Shell, lehnt sich aber in der Syntax sehr stark
an die Programmiersprache C an. Sie sollte nach Möglichkeit nicht zur
Shell-Programmierung benutzt werden, da sie an vielen Stellen nicht so
reagiert, wie man es erwarten sollte.
\end{itemize} \end{itemize}
\medskip\emph{Komfort-Shells:}\nopagebreak \medskip\emph{Komfort-Shells:}\nopagebreak
\begin{itemize} \begin{itemize}
\item Die Bourne-Again-Shell\index{Bourne-Again-Shell|textbf}\index{Shell>Bourne-Again-|see{Bourne-Again-Shell}}\index{Shell>Bash|see{Bourne-Again-Shell}} (\texttt{bash}\index{bash=\texttt{bash}|see{Bourne-Again-Shell}}) ist voll abwärtskompatibel zur sh, bietet aber von allen Shells die komfortabelsten Funktionen für das interaktive Arbeiten. Da die Bash ein GNU-Produkt ist, ist sie die Standard-Shell auf allen Linux-Systemen. Sie steht aber auch auf den meisten anderen Unixen zur Verfügung. \item Die
Die Bash unterstützt Auto-Completion\index{Auto-Completion|textbf}\footnote{Mit Auto-Completion ist das automatische Vervollständigen von Dateinamen\index{Dateinamen} gemeint.}, History-Funktionen, Aliase\index{Aliase}, eine Ganzzahl-Arithmetik und indizierte Arrays\index{Array}. Bourne-Again-Shell\index{Bourne-Again-Shell|textbf}\index{Shell>Bourne-Again-|see{Bourne-Again-Shell}}\index{Shell>Bash|see{Bourne-Again-Shell}}
(\texttt{bash}\index{bash=\texttt{bash}|see{Bourne-Again-Shell}}) ist voll
abwärtskompatibel zur sh, bietet aber von allen Shells die komfortabelsten
Funktionen für das interaktive Arbeiten. Da die Bash ein GNU-Produkt ist, ist
sie die Standard-Shell auf allen Linux-Systemen. Sie steht aber auch auf den
meisten anderen Unixen zur Verfügung. Die Bash unterstützt
Auto-Completion\index{Auto-Completion|textbf}\footnote{Mit Auto-Completion ist
das automatische Vervollständigen von Dateinamen\index{Dateinamen} gemeint.},
History-Funktionen, Aliase\index{Aliase}, eine Ganzzahl-Arithmetik und
indizierte Arrays\index{Array}.
\item Die
TENEX-C-Shell\index{TENEX-C-Shell|textbf}\index{Shell>TENEX-C-|see{TENEX-C-Shell}}
(\texttt{tcsh}\index{tcsh=\texttt{tcsh}|see{TENEX-C-Shell}}) verhält sich zur
C-Shell wie die Bourne-Again-Shell zur Standard-Shell. Sie ist voll kompatibel,
bietet aber Kom\-fort-Funk\-tio\-nen wie Kom\-man\-do\-zei\-len-Edi\-tie\-rung,
programmierbare Auto-Completion\index{Auto-Completion},
Recht\-schreib\-hil\-fen und eine History.
\item Die TENEX-C-Shell\index{TENEX-C-Shell|textbf}\index{Shell>TENEX-C-|see{TENEX-C-Shell}} (\texttt{tcsh}\index{tcsh=\texttt{tcsh}|see{TENEX-C-Shell}}) verhält sich zur C-Shell wie die Bourne-Again-Shell zur Standard-Shell. Sie ist voll kompatibel, bietet aber Komfort-Funktionen wie Kommandozeilen-Editierung, programmierbare Auto-Completion\index{Auto-Completion}, Rechtschreibhilfen und eine History. \item Die Z-Shell\index{Z-Shell|textbf}\index{Shell>Z-|see{Z-Shell}}
(\texttt{zsh}\index{zsh=\texttt{zsh}|see{Z-Shell}}) ähnelt der Korn-Shell,
\item Die Z-Shell\index{Z-Shell|textbf}\index{Shell>Z-|see{Z-Shell}} (\texttt{zsh}\index{zsh=\texttt{zsh}|see{Z-Shell}}) ähnelt der Korn-Shell, enthält aber viele Erweiterungen. Die Z-Shell unterstützt Kommandozeilen-Editing, programmierbares Auto-Completion\index{Auto-Completion}, Shell-Funktionen und eine History. Zudem ist eine Rechtschreibprüfung eingebaut. enthält aber viele Erweiterungen. Die Z-Shell unterstützt
\end{itemize} Kom\-mandozeilen-Editing, programmierbares
Auto-Completion\index{Auto-Completion}, Shell-Funktionen und eine History.
Zudem ist eine Rechtschreibprüfung eingebaut. \end{itemize}
\medskip\emph{Exoten:}\medskip\nopagebreak \medskip\emph{Exoten:}\medskip\nopagebreak
Desweiteren gibt es noch eine Reihe weiterer Shells, die aber nur selten eingesetzt werden. Dazu gehören die \texttt{ash}\index{ash|textbf}\index{Shell>ash=\texttt{ash}|see{ash}} (Ein Bourne-Shell-Clone für Rechner mit wenig Speicher.), \texttt{rc}\index{rc|textbf}\index{Shell>rc=\texttt{rc}|see{rc}} (Noch ein Bourne-Shell-Clone, ursprünglich aus AT\&T Plan 9. Klein, schnell und mit eine C-ähnlichen Syntax.), \texttt{esh}\index{esh|textbf}\index{Shell>esh=\texttt{esh}|see{esh}} (Klein und schnell, bietet eine Lisp-ähnliche Sprache), \texttt{sash}\index{sash|textbf}\index{Shell>sash=\texttt{sash}|see{sash}} (System Administrator's Shell - eine statisch gelinkte Shell mit integrierten Standard-Kommandos.). Desweiteren gibt es noch eine Reihe weiterer Shells, die aber nur selten
eingesetzt werden. Dazu gehören die
\texttt{ash}\index{ash|textbf}\index{Shell>ash=\texttt{ash}|see{ash}} (Ein
Bourne-Shell-Clone für Rechner mit wenig Speicher.),
\texttt{rc}\index{rc|textbf}\index{Shell>rc=\texttt{rc}|see{rc}} (Noch ein
Bourne-Shell-Clone, ursprünglich aus AT\&T Plan 9. Klein, schnell und mit eine
C-ähnlichen Syntax.),
\texttt{esh}\index{esh|textbf}\index{Shell>esh=\texttt{esh}|see{esh}} (Klein
und schnell, bietet eine Lisp-ähnliche Sprache),
\texttt{sash}\index{sash|textbf}\index{Shell>sash=\texttt{sash}|see{sash}}
(System Administrator's Shell - eine statisch gelinkte Shell mit integrierten
Stan\-dard-Kom\-man\-dos.).
Diese Liste ist bei weitem nicht vollständig. Diese Liste ist bei weitem nicht vollständig.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,12 @@
% $Id$
\chapter{Wo sind Unterschiede zu DOS-Batchdateien?}\index{DOS|(textbf}\index{Batchdateien|(textbf} \chapter{Wo sind Unterschiede zu DOS-Batchdateien?}\index{DOS|(textbf}\index{Batchdateien|(textbf}
Unter DOS werden Batchdateien oft dazu benutzt, lange Kommandos abzukürzen um Unter DOS werden Batchdateien oft dazu benutzt, lange Kommandos abzukürzen um
die Tipparbeit zu vermindern, oder um sich das Merken von vielen Parametern zu die Tipparbeit zu vermindern, oder um sich das Merken von vielen Parametern zu
ersparen. Diese Aufgabe überläßt man unter Unix am besten den ersparen. Diese Aufgabe überläßt man unter Unix am besten den
Shell-Aliasen\index{Aliase} oder Shell-Funktionen.\bigskip Shell-Aliasen\index{Aliase} oder Shell-Funktionen.
Shell-Skripte können viel mehr als Batchdateien.\bigskip Shell-Skripte können viel mehr als Batchdateien.
Wie der Name schon sagt, sind Batchdateien im Wesentlichen nur ein `Stapel' von Wie der Name schon sagt, sind Batchdateien im Wesentlichen nur ein `Stapel' von
Anweisungen, die nacheinander ausgeführt werden. Es stehen zwar auch einige Anweisungen, die nacheinander ausgeführt werden. Es stehen zwar auch einige
@ -23,8 +24,8 @@ DOS keine M
erste Kommando vollständig ausgeführt, seine Ausgabe in eine temporäre Datei erste Kommando vollständig ausgeführt, seine Ausgabe in eine temporäre Datei
geschrieben und danach als Eingabe für das zweite Kommando benutzt. Daß so ein geschrieben und danach als Eingabe für das zweite Kommando benutzt. Daß so ein
Verhalten unter Umständen schnell zu einer vollen Festplatte führen kann, sieht Verhalten unter Umständen schnell zu einer vollen Festplatte führen kann, sieht
man bei dem Beispiel, in dem eine CD kopiert werden soll (Kapitel \ref{cdrdao}, man bei dem Beispiel in Abschnitt \ref{cdrdao}, in dem eine CD kopiert werden
Seite \pageref{cdrdao}). soll.
Shell-Skripte kann man dagegen eher mit einer `richtigen' Programmiersprache Shell-Skripte kann man dagegen eher mit einer `richtigen' Programmiersprache
vergleichen. Es stehen alle Konstrukte zur Verfügung, die eine vergleichen. Es stehen alle Konstrukte zur Verfügung, die eine

View File

@ -1,5 +1,18 @@
% $Id$
\chapter{Wofür Shell-Programmierung?} \chapter{Wofür Shell-Programmierung?}
Natürlich stellt sich die Frage, in welchen Situationen ein Shell-Skript der
richtige Weg ist, und wann man vielleicht doch besser zu einer interpretierten
oder compilierten Sprache greift.
\section{Wofür?}
Die Shell ist der perfekte Baukasten für das Unix-Paradigma `small is
beautiful'. Die mitgelieferten Unix-Standardkommandos sind einfach gehalten,
erledigen aber auf effiziente Weise die Arbeit für die sie programmiert wurden.
Mit der Shell, bzw. dem Shell-Skript, wird aus dem Heinzelmännchen ein starker
Riese.
Shell-Skripte werden im Wesentlichen aus zwei Gründen geschrieben: Erstens, Shell-Skripte werden im Wesentlichen aus zwei Gründen geschrieben: Erstens,
weil man so ständig wiederkehrende Kommandos zusammenfassen kann, die man dann weil man so ständig wiederkehrende Kommandos zusammenfassen kann, die man dann
mit einem einfachen Aufruf starten kann, und zweitens, weil man so einfache mit einem einfachen Aufruf starten kann, und zweitens, weil man so einfache
@ -16,3 +29,19 @@ Befehlen ausf
Beispiel eine Audio-CD kopieren soll, sollte das Brennprogramm nur dann Beispiel eine Audio-CD kopieren soll, sollte das Brennprogramm nur dann
aufrufen, wenn der Einlesevorgang erfolgreich abgeschlossen wurde. aufrufen, wenn der Einlesevorgang erfolgreich abgeschlossen wurde.
\section{Wofür nicht?}
Ein Shell-Skript besteht aus einer Abfolge von System-Tool-Aufrufen. Das heißt,
für jeden Schritt in einem Skript wird ein neuer Prozeß gestartet. Das kostet
eine Menge Systemzeit, die Skripte laufen also vergleichsweise langsam. Für
komplexe, zeitkritische oder langwierige Aufgaben sollte man also besser zu
Perl, Python oder in Extremfällen zu C / C++ greifen.
Shell-Skripte können als imperativ angesehen werden, für viele Aufgaben ist
aber ein objektorientierter Ansatz wesentlich geeigneter. Auch hier ist also
der Griff zu einer anderen Sprache angeraten.
Es gibt zwar ein paar Tools\footnote{Zum Beispiel dialog im Textmodus, oder
xmessage unter X.}, mit denen auch Shell-Skripte eine grafische oder
textorientierte Benutzeroberfläche (GUI) bekommen können, aber das ist trotzdem
nicht das natürliche Terrain der Shell-Programmierung.