Viele Aenderungen, Tabellen durch Syntax-Boxen ausgetauscht, neues Kapitel: date

This commit is contained in:
rschaten
2005-01-28 10:07:07 +00:00
parent 68d30297e6
commit 82d1e3e470
27 changed files with 456 additions and 436 deletions

View File

@@ -37,7 +37,9 @@ eine entsprechende Meldung ausgegeben.
\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:
\index{\^=\texttt{\^}}\index{Anführungszeichen}\index{grep=\texttt{grep}}\index{Pipe}\index{sleep=\texttt{sleep}}\index{who=\texttt{who}}
\begin{lstlisting}
@@ -48,7 +50,67 @@ done
echo "Die Katze ist aus dem Haus, Zeit, daß die Mäuse tanzen!"
\end{lstlisting}
Die Schleife wird nämlich dann so lange ausgeführt, bis \texttt{grep}\index{grep=\texttt{grep}} einen Fehler (bzw. eine erfolglose Suche) zurückmeldet.
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{Subshell-Schleifen vermeiden}\label{subshellschleifen}
Wir wollen ein Skript schreiben, das die \texttt{/etc/passwd} liest und dabei
zählt, wie viele Benutzer eine UID kleiner als 100 haben.
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.
\section{Ein typisches Init-Skript}\label{init-skript}\index{Init-Skript}
@@ -248,7 +310,7 @@ echo "aflag=$aflag / Name = $name / Die Dateien sind $*"
\section{Fallensteller: Auf Traps reagieren}\label{traps}\index{trap=\texttt{trap}|(}\index{Signal|(}
Ein laufendes Shell-Skript kann durch Druck auf die Interrupt-Taste
(normalerweise \Ovalbox{CTRL}-\Ovalbox{C}) unterbrochen werden. Durch Druck auf
(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
@@ -342,7 +404,7 @@ der Aufrufsyntax auf die Standard-Fehlerausgabe geschrieben.
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
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.
@@ -452,7 +514,7 @@ Ausgabe von \texttt{ps} erscheint das \texttt{grep}-Kommando allerdings mit
\subsection{Dateiinhalte suchen}\label{beispiele_suchen_dateien}\index{find=\texttt{find}|(textbf}
Ein weiterer wertvoller Trick, diesmal im Zusammenhang mit \texttt{find} ist
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
@@ -468,10 +530,10 @@ alle Dateien, die dem Muster entsprechen:
\lstinline|grep -r strict *.pl|
Das führt wieder 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:
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 {} \;|