Viele Aenderungen

This commit is contained in:
rschaten
2004-12-02 13:54:06 +00:00
parent c0e556e25d
commit 15af99f29e
10 changed files with 873 additions and 57 deletions

View File

@@ -1,5 +1,5 @@
% $Id$
\chapter{Nützliche Shell-Kommandos}\label{nuetzliche_shell-kommandos}
\chapter{Werkzeugkasten}\label{werkzeugkasten}
Durch die gezeigten Steuerungsmöglichkeiten stehen dem Shell-Pro\-grammie\-rer
Mög\-lich\-kei\-ten offen, fast alle gängigen Algorithmen zu implementieren. Es
ist tatsächlich in der Shell möglich, Sortier- oder Suchfunktionen zu
@@ -68,11 +68,30 @@ Dateien auf der Festplatte.
\item \texttt{head} (\ref{head}): Dateianfang ausgeben
\item \texttt{printf} (\ref{printf}): Formatierte Datenausgabe
\item \texttt{read} (\ref{read}): Zeilen einlesen
\item \texttt{sort} (\ref{sort}): Zeilenweises Sortieren
\item \texttt{tail} (\ref{tail}): Dateiende ausgeben
\end{itemize}
\subsection{Dateiinhalte bearbeiten}\label{dateiinhalte}
Natürlich bietet die Shell eine Reihe von Befehlen, um die Inhalte von Dateien
zu bearbeiten. Diese Auflistung ist in weiten Teilen deckungsgleich mit der
Liste der Tools zur Manipulation von Pipes, auch diese Kommandos kommen also
in mehreren Situationen zum Einsatz.
\begin{itemize}
\item \texttt{awk} (\ref{awk}): In einer Pipe editieren
\item \texttt{cmp} (\ref{cmp}): Binäre Dateien vergleichen
\item \texttt{cut} (\ref{cut}): Teile einer Zeile ausschneiden
\item \texttt{diff} (\ref{diff}): Textdateien vergleichen
\item \texttt{paste} (\ref{paste}): Dateien zusammenführen
\item \texttt{sed} (\ref{sed}): In einer Pipe editieren
\item \texttt{sort} (\ref{sort}): Zeilenweises Sortieren
\item \texttt{tr} (\ref{tr}): Zeichen ersetzen
\item \texttt{uniq} (\ref{uniq}): Doppelte Zeilen suchen
\end{itemize}
\subsection{Pfade und Dateien}\label{pfade_und_dateien}
Eine der Hauptaufgaben von Shell-Skripten ist natürlich das Hantieren mit
@@ -85,10 +104,12 @@ Datei kann viel mehr sein als nur ein paar Daten im Filesystem.
\begin{itemize}
\item \texttt{basename} (\ref{basename}): Den Namen einer Datei (ohne Pfad) ausgeben
\item \texttt{cd} (\ref{cd}): Verzeichnis wechseln
\item \texttt{cp} (\ref{cp}): Dateien kopieren
\item \texttt{chgrp} (\ref{chgrp}): Gruppen-ID einer Datei ändern
\item \texttt{chmod} (\ref{chmod}): Zugriffsrechte einer Datei ändern
\item \texttt{chown} (\ref{chown}): Eigentümer einer Datei ändern
\item \texttt{cmp} (\ref{cmp}): Binäre Dateien vergleichen
\item \texttt{dirname} (\ref{dirname}): Den Pfad zu einer Datei (ohne den Namen) ausgeben
\item \texttt{find} (\ref{find}): Dateien suchen
\item \texttt{mkdir} (\ref{mkdir}): Verzeichnisse anlegen
@@ -96,6 +117,7 @@ Datei kann viel mehr sein als nur ein paar Daten im Filesystem.
\item \texttt{rm} (\ref{rm}): Dateien löschen
\item \texttt{rmdir} (\ref{rmdir}): Verzeichnisse löschen
\item \texttt{touch} (\ref{touch}): Eine leere Datei anlegen, bzw. das Zugriffsdatum einer Datei ändern
\item \texttt{which} (\ref{which}): Ausführbare Dateien suchen
\item \texttt{xargs} (\ref{xargs}): Ausgaben eines Kommandos als Parameter eines anderen Kommandos benutzen
\end{itemize}
@@ -120,12 +142,14 @@ und ausgef
kleinsten geeigneten Hammer nehmen.
\begin{itemize}
\item \texttt{awk} (\ref{awk}): In einer Pipe editieren
\item \texttt{cut} (\ref{cut}): Teile einer Zeile ausschneiden
\item \texttt{grep} (\ref{grep}): In einer Pipe suchen
\item \texttt{sed} (\ref{sed}): In einer Pipe editieren
\item \texttt{awk} (\ref{awk}): In einer Pipe editieren
\item \texttt{sort} (\ref{sort}): Zeilenweises Sortieren
\item \texttt{tee} (\ref{tee}): Datenstrom in einer Datei protokollieren
\item \texttt{tr} (\ref{tr}): Zeichen ersetzen
\item \texttt{uniq} (\ref{uniq}): Doppelte Zeilen suchen
\item \texttt{wc} (\ref{wc}): Zeilen, Wörter oder Zeichen zählen
\end{itemize}
@@ -149,6 +173,7 @@ Verf
\item \texttt{ps} (\ref{ps}): Prozeßliste ausgeben
\item \texttt{pgrep} (\ref{pgrep}): Bestimmte Prozesse suchen
\item \texttt{pkill} (\ref{pkill}): Bestimmte Prozesse töten
\item \texttt{trap} (\ref{trap}): Auf Signale reagieren
\end{itemize}
@@ -164,7 +189,154 @@ ausgiebigere Informationen empfehle ich entsprechende B
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{awk}\label{awk}\index{awk=\texttt{awk}|(textbf}
TODO!!! awk
Über die Skriptsprache \texttt{awk} wurden schon ganze Bücher geschrieben, eine
vollständige Beschreibung würde den Rahmen dieses Dokumentes bei weitem
sprengen. Hier werden nur ein paar grundlegende Techniken beschrieben, die
häufig im Zusammenhang mit Shell-Skripten auftauchen.
Oben wurde \texttt{awk} `Skriptsprache' genannt. Das ist insofern richtig, als
daß es eine mächtige und komplexe Syntax zur Verfügung stellt, um Texte
automatisiert zu bearbeiten. Es fällt somit in die gleiche Tool-Kategorie wie
\texttt{sed} (Abschnitt \ref{sed}).
Es unterscheidet sich aber in seinen grundlegenden Prinzipien entscheidend von
den meisten anderen Programmiersprachen: \texttt{awk} arbeitet `Datenbasiert'.
Das bedeutet, daß zunächst die Daten spezifiziert werden mit denen gearbeitet
werden soll, dann folgen die auszuführenden Kommandos. Das Prinzip wird schnell
klar, wenn man sich einige der Beispiele weiter unten ansieht.
\subsubsection{Aufruf}
Auch der Aufruf erfolgt analog zu \texttt{sed}: Bei einfachen Aufgaben kann das
\texttt{awk}-Programm direkt an der Kommandozeile mitgegeben werden, komplexere
Programme werden in Dateien gespeichert und von dort gelesen.
Eine weitere Gemeinsamkeit ist die Art der Ein- und Ausgabe. Wenn eine
Eingabedatei angegeben wird, wird diese verarbeitet. Ansonsten wird die
Standard-Eingabe gelesen. Ausgaben erfolgen immer auf der Standard-Ausgabe.
\footnotesize
\begin{listing}[2]{1}
# Aufruf als Filter:
kommando1 | awk '{ print $1; print $2 }' | kommando2
# Aufruf mit einer zu bearbeitenden Datei:
awk '{ print $1; print $2 }' datei.txt
# In einem Skript kann das Kommando auch über mehrere Zeilen gehen:
awk '
{
print $1;
print $2;
}' datei.txt
# Alternativ können die Kommandos auch in eine eigene Datei gespeichert und
# über den Parameter -f eingebunden werden:
awk -f script.awk datei.txt
\end{listing}
\normalsize
Neben dem Parameter \texttt{-f} zum Einlesen der Programmdatei gibt es noch den
Parameter \texttt{-F} mit dem der Feld-Trenner angegeben werden kann. Die
folgende Zeile gibt beispielsweise alle Benutzernamen und deren User-IDs aus
der Doppelpunktseparierten Datei \texttt{/etc/passwd} aus:
\texttt{awk -F: '\{ print \$1\dq hat ID \dq\$3 \}' /etc/passwd}
\subsubsection{Muster und Prozeduren}
Die Skripte für \texttt{awk} bestehen aus Blöcken von Mustern und Prozeduren.
Ein Block hat den folgenden Aufbau:
\textsl{muster}\texttt{ \{ }\textsl{prozedur}\texttt{ \}}
Dabei sind beide Bestandteile des Blockes Optional: Wird das Muster
weggelassen, wird die Prozedur auf alle Textbestandteile angewandt. Und wird
keine Prozedur angegeben, wird der betroffene Text einfach ausgegeben.
Das Muster kann dabei auf verschiedene Weise angegeben werden:
\begin{itemize}
\item Als regulärer Ausdruck (siehe Abschnitt \ref{mustererkennung}),
eingebettet in Slashes: \texttt{/}\textsl{muster}\texttt{/}
\item Als relationaler Ausdruck, bei dem bestimmte Kriterien auf die
Eingabedaten zutreffen müssen. Mit \texttt{\$2>\$1} werden beispielsweise
Zeilen angesprochen, deren zweites Feld einen größeren Wert hat als das erste.
\item Mit Operatoren für das Pattern-Matching, ähnlich wie in Perl (\texttt{\~}
oder \texttt{!\~})
\item \texttt{BEGIN} kennzeichnet Prozeduren, die vor der Bearbeitung anderer
Blöcke zum Tragen kommen sollen.
\item Analog dazu gibt es ein \texttt{END}, mit dem abschließende Aktionen
gekennzeichnet werden.
\end{itemize}
Abgesehen von \texttt{BEGIN} und \texttt{END} können die Muster auch durch
logische Operatoren (\texttt{\&\&}, \texttt{||} oder \texttt{!}) kombiniert
werden. Durch Komma getrennt besteht die Möglichkeit, Wirkungsbereiche zu
definieren.
Die Prozeduren können Variablen- oder Array-Zuweisungen, Ausgabeanweisungen,
Funktionsaufrufe oder Kontrollstrukturen enthalten.
\subsubsection{Variablen}
Es gibt in \texttt{awk} eine Reihe eingebauter Variablen, die in Mustern oder
Prozeduren verwendet werden können:
\LTXtable{\textwidth}{tab_kommandos_awk_variablen.tex}
Eigene Variablen können nach Belieben verwendet werden, siehe dazu das Beispiel
mit den TeX-Dateien weiter unten.
\subsubsection{Beispiele}
Hier ein paar Einfache Beispiele für Blocks aus Mustern und Prozeduren:
\footnotesize
\begin{listing}[2]{1}
# Das erste Feld jeder Zeile ausgeben:
{ print $1 }
# Alle Zeilen ausgeben, die 'regexp' enthalten:
/regexp/
# Das erste Feld jeder Zeile ausgeben, die 'regexp' enthält:
/regexp/ { print $1 }
# Datensätze mit mehr als zwei Feldern auswählen:
NF > 2
# Das dritte und das zweite Feld jeder Zeile ausgeben, deren erstes Feld den
# String 'WICHTIG' enthält:
$1 ~ /WICHTIG/ { print $3, $2 }
# Die Vorkommen von 'muster' zählen, und deren Anzahl ausgeben:
/muster/ { ++x }
END { print x }
# Alle Zeilen mit weniger als 23 Zeichen ausgeben:
length($0) < 23
# Alle Zeilen ausgeben, die mit 'Name:' anfangen und exakt sieben Felder
# enthalten:
NF == 7 && /^Name:/
# Alle Felder der Eingabedaten zeilenweise in umgekehrter Reihenfolge ausgeben:
{
for (i = NF; i >= 1; i--)
print $i
}
# Die Größe aller TeX-Dateien addieren, die Summe in kB umrechnen und ausgeben,
# verarbeitet die Ausgabe von 'ls -l':
/.*tex/ { summe += $5 }
END { summe /= 1024; print "Die Größe aller TeX-Files beträgt", summe, "kB" }
# Pipe-Separierte Liste aller gemounteten Partitionen und derer Füllstände
# ausgeben, verarbeitet die Ausgabe von 'df':
BEGIN { OFS="|" }
/^\/dev\// { print $1,$5 }
\end{listing}
\normalsize
\index{awk=\texttt{awk}|)}
@@ -220,6 +392,14 @@ werden.
\index{cat=\texttt{cat}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{cd}\label{cd}\index{cd=\texttt{cd}|(textbf}
Mit dem Kommando \texttt{cd} wird das aktuelle Verzeichnis gewechselt.
\index{cd=\texttt{cd}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{chgrp}\label{chgrp}\index{chgrp=\texttt{chgrp}|(textbf}
@@ -328,6 +508,14 @@ diese Datei nicht allgemein lesbar ist.
\index{chpasswd=\texttt{chpasswd}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{cmp}\label{cmp}\index{cmp=\texttt{cmp}|(textbf}
TODO!!! cmp GNU?
\index{cmp=\texttt{cmp}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{cp}\label{cp}\index{cp=\texttt{cp}|(textbf}
@@ -355,9 +543,20 @@ der Formate N, N-, N-M oder -M benutzt werden.
\LTXtable{\textwidth}{tab_kommandos_cut_beispiele.tex}
Praktisch das Gegenstück zu \texttt{cut} ist \texttt{paste}, damit werden
Dateien in Spalten zusammengeführt. Nährers dazu in Abschnitt \ref{paste}.
\index{cut=\texttt{cut}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{diff}\label{diff}\index{diff=\texttt{diff}|(textbf}
TODO!!! diff
\index{diff=\texttt{diff}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{dirname}\label{dirname}\index{dirname=\texttt{dirname}|(textbf}
@@ -437,7 +636,72 @@ Arith\-me\-tik-Ex\-pan\-sion (Siehe \ref{arithmetikexpansion}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{find}\label{find}\index{find=\texttt{find}|(textbf}
TODO!!! find
Auf einem modernen System sind nicht selten mehrere zehn- oder hunderttausend
Dateien vorhanden. Um eine bestimmte Datei anhand komplexer Kriterien ausfindig
zu machen benutzt man \texttt{find}.
Bei einem Aufruf wird zuerst das zu durchsuchende Verzeichnis, dann die
Suchkriterien und eventuell abschließend die durchzuführenden Aktionen
angegeben.
Die Angabe der Suchkriterien ist sehr vielseitig, hier werden nur die
wichtigsten Optionen beschrieben. Wie immer empfehle ich das Studium der
Man-Page oder eines entsprechenden Buches.
\LTXtable{\textwidth}{tab_kommandos_find_parameter.tex}
Die verschiedenen Suchkriterien können kombiniert werden. Mit \texttt{-a} oder
\texttt{-o} erreicht man eine logische AND- bzw. OR-Verknüpfung, mit einem
vorangestellten \texttt{!} können Kriterien negiert werden. Die AND-Verknüpfung
muß nicht explizit angegeben werden, wenn mehrere Kriterien verwandt werden.
Komplexere Ausdrücke können durch runde Klammern gruppiert werden, dabei ist
jedoch deren Sonderbedeutung in der Shell entsprechend zu quoten (Siehe
Abschnitt \ref{quoting}).
Bei der Angabe numerischer Parameter zu den Suchkriterien wird normalerweise
nach dem exakten Wert gesucht. Statt eines einfachen \textsl{n} kann jedoch
auch \textsl{+n} oder \textsl{-n} angegeben werden, damit wird dann nach
Vorkommen größer bzw. kleiner als \textsl{n} gesucht.
Da die reine Beschreibung der Parameter manchmal etwas verwirrend ist, folgen
hier ein paar praktische Beispiele:
\footnotesize
\begin{listing}[2]{1}
# Suche alle Einträge in bzw. unter dem aktuellen Verzeichnis:
find .
# Suche alle normalen Dateien mit der Endung txt unter /home:
find /home -type f -name \*.txt
# Suche alle Einträge außer symbolischen Links, in die jeder schreiben darf:
find / \! -type l -perm 777
# Suche alle Dateien unter dem Homeverzeichnis, deren Größe 10000000 Bytes
# übersteigt und gib sie ausführlich aus:
find ~ -size +10000000c -exec ls -l {} \;
# Suche alle Einträge im Homeverzeichnis, die innerhalb der letzten zwei Tage
# geändert wurden:
find ~ -mtime -2
\end{listing}
\normalsize
Wenn mittels \texttt{-exec} weitere Kommandos gestartet werden, sollte beachtet
werden daß mindestens ein Prozeß pro Fundstelle gestartet wird. Das kostet sehr
viel, unter Umständen macht der Einsatz von \texttt{xargs} (Abschnitt
\ref{xargs}) Sinn.
Die Ausführung von \texttt{find} erzeugt unter Umständen sehr viel Last auf der
Festplatte, bei Netzlaufwerken auch Netzwerkbandbreite. In einigen Fällen
bieten sich alternative Suchverfahren an:
\textbf{Alternative 1:} Falls man den Namen der zu suchenden Datei kennt, und
das Locate-System installiert ist kann man die Datei auch mittels
\texttt{locate} suchen. Das ist ressourcenschonender, da nicht `live' das
Filesystem durchforstet wird, sondern nur die Locate-Datenbank. Diese wird
allerdings im Regelfall nur einmal täglich aktualisiert, die Suche taugt nicht
für schnell wechselnde Bestände.
\textbf{Alternative 2:} Sucht man nach einer ausführbaren Datei, die im Pfad
vorhanden ist (`Wo liegt eigentlich Firefox?'), dann sucht man mittels
\texttt{which} (Abschnitt \ref{which}).
Siehe auch: Abschnitt \ref{beispiele_suchen_dateien}.
@@ -473,11 +737,44 @@ werden allerdings nicht die letzten Zeilen angezeigt, sondern die ersten.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{kill}\label{kill}\index{kill=\texttt{kill}|(textbf}
TODO!!! kill
Die landläufige Annahme ist, daß man mit dem \texttt{kill}-Kom\-man\-do
Prozesse `umbringt'. Das ist zwar wahr, aber nicht die ganze Wahrheit.
Übrigens: Die landläufige Annahme ist, daß man mit dem
\texttt{kill}-Kom\-man\-do Prozesse `umbringt'. Das ist zwar wahr, aber nicht
die ganze Wahrheit.
Im Prinzip sendet \texttt{kill} lediglich ein Signal an einen Prozeß. Ohne
weitere Parameter ist das tatsächlich ein SIGTERM, das den Prozeß im Regelfall
dazu bewegt sich zu beenden. Jeder Admin kennt das Verfahren, einem hängenden
Prozeß mittels \texttt{kill -9} den Gnadenschuß zu geben. Die 9 steht dabei für
das Signal mit der Nummer 9, SIGKILL. Noch ein gebräuchliches Signal ist SIGHUP
(1), der `Hangup'. Historisch wurde das gesendet wenn die Leitung zum Rechner
aufgelegt wurde, mittlerweile ist es gängige Praxis damit einen Daemon neu zu
initialisieren.
Daneben stehen noch eine Reihe weiterer Signale zur Verfügung. Mit \texttt{kill
-l} kann man sich eine Liste ansehen.
Es gibt verschiedene Wege, das Signal abzusetzen. Welchen man wählt ist
Geschmackssache. Hier ein paar Beispiele:
\footnotesize
\begin{listing}[2]{1}
# Die folgenden Befehle sind gleichwertig. Alle senden ein HUP an Prozeß-ID 42:
kill -1 42
kill -HUP 42
kill -SIGHUP 42
kill -s 1 42
kill -s HUP 42
kill -s SIGHUP 42
# virtueller Selbstmord: Alle Prozesse umbringen, die man umbringen kann:
kill -9 -1
# SIGTERM an mehrere Prozesse senden:
kill 123 456 789
\end{listing}
\normalsize
Siehe auch: Das Beispiel `Fallensteller' in Abschnitt \ref{traps} zeigt, wie
ein Skript auf Signale reagieren kann.
\index{kill=\texttt{kill}|)}
@@ -509,14 +806,45 @@ zur Verf
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{ls}\label{ls}\index{ls=\texttt{ls}|(textbf}
Den Inhalt von Verzeichnissen im Dateisystem bringt man mit \texttt{ls} in
Erfahrung. Ein einfacher Aufruf listet lediglich die Dateinamen im aktuellen
oder angegebenen Verzeichnis auf, das Kommando hat aber auch sehr viele
Parameter mit denen sich die Ausgabe anpassen läßt. Hier sind die wichtigsten,
eine vollständige Auflistung bietet wie immer die Man-Page:
\LTXtable{\textwidth}{tab_kommandos_ls_parameter.tex}
Besonders informativ gibt sich der Parameter \texttt{-l}, da damit auch die
Eigentümer und die Berechtigungen der Dateien angezeigt werden. Die Ausgabe hat
die folgende Form:
\texttt{-rw-r--r-- 1 rschaten users 6252 Nov 19 14:14 shell.tex}
Die linke Spalte der Ausgabe zeigt die bestehenden Berechtigungen. Es ist ein
Block in der Form `drwxrwxrwx'. An Stelle des d können auch andere Buchstaben
stehen, hier wird der Dateityp angegeben, also ob es sich um eine einfache
Datei (-), ein Verzeichnis (d), einen Link (l) oder ähnliches\footnote{Siehe
Man-Page} handelt. An Stelle der rwx-Blöcke können auch Striche stehen, die
stehen für nicht gesetzte Attribute.
Man-Page} handelt. Die rwx-Blöcke geben die Dateiberechtigungen jeweils für den
Besitzer, die Gruppe und andere User an. Dabei steht das r für read, w für
write und x für execute. An ihrer Stelle können auch Striche stehen, die
repräsentieren nicht gesetzte Attribute. Die Datei im Beispiel ist also für
ihren Besitzer les- und schreibbar, für alle anderen nur lesbar. Die
Berechtigungen werden mit dem Kommando \texttt{chmod} (Abschnitt \ref{chmod})
gesetzt.
TODO!!! ls
Die nächste Spalte stellt die Anzahl der Links dar, die auf diese Datei
verweisen, im Beispiel existiert die Datei an nur einer Stelle im Filesystem.
Dann folgen der Benutzer und die Gruppe, denen die Datei gehört. Diese
Parameter werden mit \texttt{chown} (Abschnitt \ref{chown}) bzw. \texttt{chgrp}
(Abschnitt \ref{chgrp}) gesetzt.
Es folgt die Größe der Datei in Bytes, sowie das Datum der letzten Änderung.
Liegt dieses mehr als ein halbes Jahr zurück wird an Stelle der Uhrzeit die
Jahreszahl angegeben, es gilt also Vorsicht walten zu lassen, wenn dieser Wert
in Skripten benutzt werden soll.
Abschließend wird der Name der jeweiligen Datei ausgegeben.
\index{ls=\texttt{ls}|)}
@@ -545,6 +873,25 @@ wird der Vorgang interaktiv, vor jeder Dateibewegung wird nachgefragt.
\index{mv=\texttt{mv}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{paste}\label{paste}\index{paste=\texttt{paste}|(textbf}
Während mit \texttt{cut} (Abschnitt \ref{cut}) Dateien spaltenweise zerlegt
werden, werden sie mit \texttt{paste} zusammengeführt. Die Dateinamen werden
als Parameter übergeben, woraufhin Zeile für Zeile die Inhalte aller Dateien zu
einer Tabelle gemacht werden.
Die Spalten werden standardmäßig durch Tabulatorzeichen getrennt, man kann mit
dem Parameter \texttt{-d} auch ein oder mehrere andere Trennzeichen definieren.
Werden mehrere Zeichen angegeben, werden sie der Reihe nach zum trennen der
Spalten benutzt.
Mit \texttt{-s} wird die Tabelle transponiert, also praktisch um 90 Grad
gedreht.
\index{paste=\texttt{paste}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{pgrep}\label{pgrep}\index{pgrep=\texttt{pgrep}|(textbf}
@@ -640,7 +987,65 @@ dazu steht im Abschnitt
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{ps}\label{ps}\index{ps=\texttt{ps}|(textbf}
TODO!!! ps
Mit \texttt{ps} gibt man einen Schnappschuß des Zustandes der aktuell laufenden
Prozesse aus\footnote{Wenn man interaktiv den Zustand der laufenden Prozesse
beobachten möchte, benutzt man \texttt{top}, das eignet sich jedoch nicht zur
Shell-Programmierung und wird deshalb nicht ausführlich beschrieben.}.
Ohne weitere Parameter listet \texttt{ps} alle Prozesse auf, die dem
aufrufenden Benutzer gehören und die mit dem aktuellen Terminal assoziiert
sind. Angezeigt werden dann die Prozeß-ID, das Terminal, die verbrauchte
CPU-Zeit und der Name des laufenden Kommandos.
In Skripten möchte man üblicherweise feststellen, ob ein bestimmtes Kommando
aktiv ist, ob also zum Beispiel ein bestimmter Serverdienst läuft. Dazu macht
man \texttt{ps} über Optionen gesprächiger.
Das Kommando versteht in der GNU-Version zwei unterschiedliche Arten von
Optionen. Den sogenannten Unix- bzw. Posix-Stil und den BSD-Stil. Zusätzlich
gibt es noch ausführliche Parameter, aber die sollen hier nicht beschrieben
werden. Die jeweiligen Formen stehen nicht auf allen Systemen zur Verfügung,
wenn ein Skript beispielsweise auch unter Solaris benutzt werden soll ist man
gezwungen, die Unix-Parametrisierung zu benutzen.
Unix-Parameter zeichnen sich durch die übliche Angabe mit Bindestrich aus.
BSD-Pa\-ra\-me\-ter werden ohne Bindestrich angegeben, was neben den meisten
anderen Kommandos etwas ungewohnt aussieht.
Es gibt sehr viele verschiedene Parameter, die beste Informationsquelle ist wie
immer die Man-Page bzw. ein entsprechendes Buch. Hier werden nur ein paar
typische Aufrufbeispiele gezeigt, deren Ausgabe sich jeder selber ansehen kann:
\footnotesize
\begin{listing}[2]{1}
# Alle Prozesse auflisten, Unix-Syntax:
ps -e
ps -ef
ps -eF
ps -ely
# Alle Prozesse auflisten, BSD-Syntax:
ps ax
ps axu
# Prozeßbaum ausgeben. Das ist in Skripten weniger Sinnvoll, wird hier aber
# angegeben weil es so eine praktische Funktion ist... :-)
ps -ejH
ps axjf
# Alle Prozesse ausgeben, die nicht dem Benutzer `root' gehören:
ps -U root -u root -N
# Nur die Prozeß-ID von Syslog ausgeben:
ps -C syslogd -o pid=
# Nur den Namen des Prozesses mit der ID 42 ausgeben:
ps -p 42 -o comm=
\end{listing}
\normalsize
Für die Suche nach Prozessen bestimmten Namens steht auf manchen Systemen auch
das Kommando \texttt{pgrep} (Abschnitt \ref{pgrep}) zur Verfügung.
Siehe auch: Abschnitt \ref{beispiele_suchen_prozesse}.
@@ -755,7 +1160,203 @@ debuggen, da sowohl Ein- als auch Ausgaben in dem Logfile sichtbar sind.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{sed}\label{sed}\index{sed=\texttt{sed}|(textbf}
TODO!!! sed
Der `Stream Editor' \texttt{sed} stellt, ähnlich wie \texttt{awk} (Abschnitt
\ref{awk}) eigentlich eine eigene Skriptsprache dar. Er wird auch
`nicht-interaktiver Editor' genannt. Die Kommandos sind minimalistisch, aber
exakt auf die Aufgabe zugeschnitten.
\texttt{sed} liest Zeilenweise aus einer Datei, wenn keine Datei angegeben
wurde wird von der Standard-Eingabe gelesen. Auf die eingelesenen Zeilen wird
dann ein mehr oder weniger kompliziertes \texttt{sed}-Skript angewendet, bevor
auf der Standard-Ausgabe die Resultate ausgegeben werden.
Eine vollständige Beschreibung von \texttt{sed} würde an dieser Stelle den
Rahmen sprengen, es gibt aber im Handel gute Bücher zu dem Thema. Hier sollen
nur die gängigsten Kommandos und einige Anwendungsbeispiele genannt werden.
\subsubsection{Aufruf}
\footnotesize
\begin{listing}[2]{1}
# Aufruf als Stream-Editor:
kommando1 | sed 's/alt/neu/' | kommando2
# Aufruf mit einer zu bearbeitenden Datei:
sed 's/alt/neu/' datei.txt
# Wenn mehr als ein Kommando ausgeführt werden soll, muß der Parameter -e
# verwendet werden:
sed -e 's/alt/neu/' -e '/loeschen/d' datei.txt
# Man kann auch mehrere Kommandos mit einem -e aufrufen, wenn sie durch ein
# Semikolon getrennt werden:
sed 's/alt/neu/; /loeschen/d' datei.txt
# In einem Skript kann das Kommando auch über mehrere Zeilen gehen:
sed '
s/alt/neu/
/loeschen/d' datei.txt
# Alternativ können die Kommandos auch in eine eigene Datei gespeichert und
# über den Parameter -f eingebunden werden:
sed -f script.sed datei.txt
\end{listing}
\normalsize
Neben den oben erwähnten Parametern kann \texttt{sed} auch mit \texttt{-n}
ruhig gestellt werden. Damit werden die Zeilen nur dann ausgegeben, wenn das
mittels `p' explizit gefordert wird. Die GNU-Version stellt noch ein paar
Parameter zur Verfügung, die Man-Page verrät näheres.
\subsubsection{Addressierung}
Durch die Adressierung können Befehle gezielt auf bestimmte Zeilen angewandt
werden. Dabei können einem Befehl keine, eine oder zwei Adressen mitgegeben
werden.
Wenn keine Zeilen adressiert werden, wirkt der Befehl auf alle Zeilen.
Wenn eine Adresse mitgegeben wird, wirkt der Befehl auf alle Zeilen die durch
diese Adresse angesprochen werden. Das können, zum Beispiel bei einem regulären
Ausdruck, auch mehrere Zeilen sein.
Werden zwei Adressen angegeben, wirkt der Befehl auf die erste betroffene
Zeile, sowie auf alle weiteren bis zur zweiten angegebenen Zeile. Die beiden
Adressen müssen durch ein Komma getrennt angegeben werden.
Die Auswahl der Zeilen kann durch ein an die Adresse angehängtes Rufzeichen
negiert werden, der Befehl wirkt dann also auf alle Zeilen die \textbf{nicht}
adressiert wurden.
Aber wie sehen solche Adreßangeben aus? Die folgende Tabelle zeigt einige
Beispiele anhand des Kommandos `d', mit dem Zeilen gelöscht werden:
\LTXtable{\textwidth}{tab_kommandos_sed_adressen.tex}
Adressen können auch vor geschweiften Klammern stehen, dann wirken sie auf die
komplette Befehlsfolge innerhalb der Klammern.
\subsubsection{Kommandos}
Es gibt eine ganze Reihe von Kommandos, diese Beschreibung konzentriert sich
aber auf die wichtigsten `Brot und Butter-Kommandos'. In den Beispielen weiter
unten kommen auch andere Kommandos vor, die können bei Bedarf anhand der
einschlägigen Quellen nachgeschlagen werden.
\LTXtable{\textwidth}{tab_kommandos_sed_kommandos.tex}
Mit \texttt{s} wird substituiert. Das heißt, in der Eingabezeile wird nach
einem Muster gesucht, und im Erfolgsfall wird es ersetzt. Wichtigster
Modifikator für dieses Kommando ist \texttt{g}, damit wird `global' ersetzt,
falls mehrere Fundstellen in einer Zeile vorkommen. Der Aufruf sieht wie folgt
aus:
\texttt{s/Suchmuster/Ersatzmuster/g}
Im Ersatzmuster können auch Teile der Fundstelle wieder vorkommen, wenn sie
durch Klammern in einen Puffer kopiert werden:
\texttt{s/Seite ([0-9]*) von ([0-9]*)/\textbackslash{}1 aus \textbackslash{}2/}
Mit \texttt{y} hingegen werden einzelne Buchstaben durch andere vertauscht. Das
folgende Kommando wandelt alle eingehenden Kleinbuchstaben in Großbuchstaben
um\footnote{Umlaute und Sonderzeichen ausgeschlossen}:
\texttt{y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/}
Normalerweise werden alle Eingabezeilen nach der Bearbeitung wieder ausgegeben,
unabhängig davon ob sie verändert wurden oder nicht. Das Verhalten kann über
den Kommandozeilenparameter \texttt{-n} abgeschaltet werden. Da dann allerdings
nichts mehr ausgegeben wird kann durch ein an ein Kommando angehängtes
\texttt{p} bestimmt werden, daß die Veränderten Zeilen~--~und nur
die~--~ausgegeben werden.
\subsubsection{Beispiele}
Da es in diesem Text nicht um \texttt{sed}-Skripte, sondern um Shell-Skripte
gehen soll werden hier keine komplexen Sachen vorgestellt, sondern nur ein paar
Einzeiler. Nichtsdestotrotz können es auch diese unscheinbaren Aufrufe in sich
haben.
\footnotesize
\begin{listing}[2]{1}
### SUCHEN UND ERSETZEN
# Im kompletten Text 'rot' durch 'blau' ersetzen:
sed 's/rot/blau/' # Ersetzt nur das erste Vorkommen in jeder Zeile
sed 's/rot/blau/4' # Ersetzt nur das vierte Vorkommen in jeder Zeile
sed 's/rot/blau/g' # Ersetzt nur jedes Vorkommen in jeder Zeile
# 'rot' durch 'blau' ersetzen, aber NUR in Zeilen die auch 'gelb' enthalten:
sed '/gelb/s/rot/blau/g'
# 'rot' durch 'blau' ersetzen, AUSSER in Zeilen die auch 'gelb' enthalten:
sed '/gelb/!s/rot/blau/g'
# 'rosa', 'hellrot' und 'magenta' durch 'pink' ersetzen:
sed 's/rosa/pink/g;s/hellrot/pink/g;s/magenta/pink/g'
gsed 's/rosa\|hellrot\|magenta/pink/g' # nur in GNU sed
# Jede Zeile um fünf Leerzeichen einrücken:
# lies: 'ersetze jeden Zeilenanfang durch fünf Leerzeichen'
sed 's/^/ /'
# Führende Blanks (Leerzeichen, Tabulatoren) von den Zeilenanfängen löschen:
# ACHTUNG: An Stelle des \t muß der Tabulator gedrückt werden, die Darstellung
# als \t versteht nicht jedes sed!
sed 's/^[ \t]*//'
# Schliessende Blanks vom Zeilenende löschen, siehe oben:
sed 's/[ \t]*$//'
# Führende und schließende Blanks löschen:
sed 's/^[ \t]*//;s/[ \t]*$//'
# Wenn eine Zeile mit Backslash aufhört den Zeilenumbruch entfernen:
sed -e :a -e '/\\$/N; s/\\\n//; ta'
### BESTIMMTE ZEILEN AUSGEBEN
# Nur Zeile 42 ausgeben:
sed -n '42p' # Methode 1
sed '42!d' # Methode 2
# Nur die Zeilen 23-42 ausgeben (inklusive):
sed -n '23,42p' # Methode 1
sed '23,42!d' # Methode 2
# Von einem regulären Ausdruck bis zum Dateiende ausgeben:
sed -n '/regexp/,$p'
# Den Bereich zwischen zwei regulären Ausdrücken ausgeben (inklusive):
sed -n '/rot/,/blau/p'
# Nur Zeilen mit mindestens 42 Zeichen ausgeben:
sed -n '/^.\{42\}/p'
# Nur Zeilen mit höchstens 42 Zeichen ausgeben:
sed -n '/^.\{42\}/!p' # Methode 1, analog zu oben
sed '/^.\{42\}/d' # Methode 2, einfachere Syntax
### BESTIMMTE ZEILEN LÖSCHEN
# Die ersten zehn Zeilen löschen:
sed '1,10d'
# Die letzte Zeile löschen:
sed '$d'
# Alles außer dem Bereich zwischen zwei regulären Ausdrücken ausgeben:
sed '/rot/,/blau/d'
# Alle Leerzeilen löschen:
sed '/^$/d' # Methode 1
sed '/./!d' # Methode 2
# Alle Leerzeilen am Dateianfang löschen:
sed '/./,$!d'
\end{listing}
\normalsize
\index{sed=\texttt{sed}|)}
@@ -882,6 +1483,113 @@ Referenzdatei angepa
\index{touch=\texttt{touch}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{tr}\label{tr}\index{tr=\texttt{tr}|(textbf}
Will man ganze Worte oder komplexe Muster in Dateien oder Pipes suchen und
ersetzen, greift man üblicherweise zu \texttt{sed} (Abschnitt \ref{sed}). Für
einzelne Buchstaben nimmt man hingegen \texttt{tr}.
Normalerweise wird \texttt{tr} mit zwei Zeichenketten als Parametern
aufgerufen und übernimmt die zu konvertierenden Daten von der Standard-Eingabe.
Jedes Zeichen im eingehenden Datenstrom wird anhand der beiden Zeichenketten
ersetzt, dabei wird das erste Zeichen der ersten Kette durch das erste Zeichen
der zweiten Kette ersetzt, das zweite durch das zweite, und so weiter.
Ist die zweite Zeichenkette länger als die erste, werden überschüssige Zeichen
ignoriert. Ist die zweite Zeichenkette kürzer als die erste, wird ihr letztes
Zeichen so lange wiederholt bis sie gleich sind. Durch den Parameter
\texttt{-t} kann dieses Verhalten abgeschaltet werden, so daß überschüssige
Zeichen abgeschnitten werden.
Mit dem Parameter \texttt{-c} wird die erste Zeichenkette `invertiert', es
werden also alle Zeichen ersetzt die nicht darin vorkommen.
\texttt{tr} kann aber auch mit nur einer Zeichenkette aufgerufen werden, wenn
die Parameter \texttt{-d} oder \texttt{-s} benutzt werden. Mit \texttt{-d}
werden alle Zeichen aus dem Eingabestrom gelöscht, die in der Zeichenkette
vorkommen. Mit \texttt{-s} werden doppelt vorkommende Zeichen durch ein
einzelnes ersetzt.
Die Zeichenketten an sich können übrigens nicht nur Buchstaben oder Zahlen
enthalten, sondern auch Sonderzeichen oder Zeichenklassen. Näheres dazu steht
in der Man-Page.
Die folgenden Beispiele verdeutlichen die Anwendung:
\footnotesize
\begin{listing}[2]{1}
text="Dies ist ein Testtext"
# kleine Umlaute durch grosse ersetzen:
echo "$text" | tr aeiou AEIOU
# -> DIEs Ist EIn TEsttExt
# Kleinbuchstaben durch Großbuchstaben ersetzen:
echo "$text" | tr a-z A-Z
# -> DIES IST EIN TESTTEXT
# alle Vokale durch Unterstriche ersetzen:
echo "$text" | tr aeiouAEIOU _
# -> D__s _st __n T_stt_xt
# Großbuchstaben löschen:
echo "$text" | tr -d A-Z
# -> ies ist ein esttext
# doppelte Buchstaben löschen:
echo "$text" | tr -s "a-zA-Z"
# -> Dies ist ein Testext
# doppelte Buchstaben löschen, mit Zeichenklasse:
echo "$text" | tr -s "[:alpha:]"
# -> Dies ist ein Testext
\end{listing}
\normalsize
\index{tr=\texttt{tr}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{trap}\label{trap}\index{trap=\texttt{trap}|(textbf}
Wie alle anderen Prozesse in einem Unix-System auch, so können auch
Shell-Skripte Signale empfangen. Diese können durch Kommandos wie \texttt{kill}
(Abschnitt \ref{kill}) geschickt worden sein, oder zum Beispiel durch einen
Tastatur-Interrupt.
Mit \texttt{trap} kann ein Skript darauf vorbereitet werden, ein oder mehrere
Signale zu empfangen. Beim Aufruf wird eine Aktion mitgegeben, und eine oder
mehrere Bedingungen die zum Ausführen der Aktion führen sollen. Das folgende
Kommando gibt zm Beispiel eine Fehlermeldung aus wenn sein Skript ein Signal 1
(HUP), 2 (INT) oder 15 (TERM) erhält:
\texttt{trap 'echo \dq`basename \$0`: Ooops...\dq 1>\&2' 1 2 15}
Die Zeile ist dem Beispiel aus Abschnitt \ref{traps} entnommen, dort findet
sich auch nochmal eine ausführliche Erklärung.
\index{trap=\texttt{trap}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{uniq}\label{uniq}\index{uniq=\texttt{uniq}|(textbf}
Mit dem Kommando \texttt{uniq} werden doppelt vorkommende Zeilen in einer
Eingabedatei oder der eingehenden Pipe (Standard-Eingabe) bearbeitet. Per
default steht `bearbeitet' an dieser Stelle für `gelöscht', aber durch
Parameter kann dieses Verhalten angepaßt werden:
\LTXtable{\textwidth}{tab_kommandos_uniq_parameter.tex}
Achtung: \texttt{uniq} betrachtet beim Vergleich nur direkt aufeinander
folgende Zeilen. Sollen alle Duplikate Dateiweit betrachtet werden, bietet sich
ein `vorsortieren' mit \texttt{sort} (Abschnitt \ref{sort}) an, vielleicht
sogar ausschließlich ein \texttt{sort -u}.
\index{uniq=\texttt{uniq}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{wc}\label{wc}\index{wc=\texttt{wc}|(textbf}
@@ -898,6 +1606,19 @@ Der Parameter \texttt{-L} gibt die L
\index{wc=\texttt{wc}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{which}\label{which}\index{which=\texttt{which}|(textbf}
Sucht im Pfad (vordefinierte Variable
\texttt{\$PATH}\index{\$PATH=\texttt{\$PATH}}, siehe Abschnitt
\ref{vordefinierte_variablen}) nach einer Ausführbaren Datei. Wenn mehrere
Dateien auf das Suchwort passen wird die erste Fundstelle ausgegeben, also die
Datei die tatsächlich ausgeführt würde. Mit \texttt{-a} werden alle Fundstellen
ausgegeben.
\index{which=\texttt{which}|)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{who}\label{who}\index{who=\texttt{who}|(textbf}