Beschreibung: Prüfungskandidaten sollten in der Lage sein, Filter auf Textströme anzuwenden. Dieses Lernziel beinhaltet das Senden von Textdateien und -ausgaben durch Textfilterprogramme, um die Ausgabe zu modifizieren, und die Verwendung von Standard-Unix-Kommandos, die im GNU textutils Paket enthalten sind.
Die wichtigsten Dateien, Bezeichnungen und Anwendungen:
Ein Beispiel mag das verdeutlichen:
Sie haben 500 Textdateien, in denen immer wieder der Begriff "Synopsis" vorkommt. Sie wollen diesen Begriff nach "Syntax" ändern. Außerdem soll jeweils die 3. Zeile jeder dieser Dateien gelöscht werden. Das wäre unglaublich viel Arbeit, hätten wir nicht das Programm sed. Der Streameditor erlaubt uns verschiedene Aktionen auf einen Datenstrom auszuführen. Dazu erstellen wir eine Datei, die die notwendigen Befehle enthält. Nennen wir sie "befehle":
1,$s/Synopsis/Syntax/g 3dJede Zeile enthält einen Befehl. Jeder Befehl besteht aus einer Adress-Angabe und dem Befehl selbst. Die erste Zeile hat die Adressangabe 1,$, was soviel heißt wie von der ersten Zeile bis zum Dateiende. Der Befehl ist s - das steht für substitute - also ersetzen. Der Befehl s hat die Form:
s/Suchbegriff/Ersetzungsbegriff/Optionen
Als Option haben wir g benutzt, was heißt, daß eine Zeile global durchsucht werden soll, nicht nur das erste Auftreten, sondern jedes soll ersetzt werden.
Die zweite Zeile unserer Datei ist noch einfacher, ihr Adress-Teil ist einfach die 3 und meint also Zeile 3. Der Befehl ist d und steht für delete also löschen. Es ist also die Anweisung, die Zeile 3 zu löschen.
Um diese Befehlsdatei jetzt anzuwenden, schreiben wir nur noch:
sed -f befehle Datei > Datei_neuund schon wurde die Datei Datei bearbeitet. Das Ergebnis steht jetzt in Datei_neu. Eine kleine Schleife konstruiert, und schon könnten wir alle 500 Dateien mit einem Aufwasch bearbeiten...
Wie gesagt, die LPI 101-Prüfung besteht nicht darauf, daß Sie den sed vollständig beherrschen, aber ein paar Übungen dazu sind nicht verkehrt. Genauere Beschreibungen, was dieses Programm für Befehle versteht finden Sie auf der sed-Handbuchseite.
Normalerweise werden die ganzen Zeilen verglichen, um sie zu sortieren. Es ist aber auch möglich, Zeilen nach einem bestimmten Positionsfeld zu sortieren. Ein Beispiel:
Der Befehl ls -l gibt uns eine Liste aller Dateien im aktuellen Verzeichnis aus. Ab Spalte 31 steht die Dateigröße. Würden wir den Befehl
ls -l | sorteingeben, dann würden die gesamten Zeilen sortiert. Das macht wenig Sinn, denn die Zeilen beginnen ja immer mit der Angabe der Zugriffsrechte und die zu sortieren ist sicher nicht das, was wir wollen. Um die Ausgabe nach Dateigröße zu sortieren können wir eingeben:
ls -l | sort +0.32Dabei bedeutet 0.32 das erste Feld (0) und davon alles, ab dem 31. Buchstaben. (Die Angabe von Feldern bezieht sich auf Dateien, die tatsächlich feldorientiert aufgebaut sind, wie etwa /etc/passwd)
Alle Optionen und Möglichkeiten entnehmen Sie wieder der sort-Handbuchseite.
Über Kommandozeilenparameter kann zudem eingestellt werden, daß nur bestimmte Teile einer Zeile verglichen werden, um die Gleichheit festzustellen. Die genauen Parameter sind der uniq-Handbuchseite zu entnehmen.
Um z.B. alle Usernamen aus der Datei /etc/passwd zu schneiden benutzen wir die Feldbegrenzer : und wollen nur das erste Feld sehen:
cut -d: -f1 /etc/passwdWenn wir aus der Liste aller laufender Prozesse die PIDs ausschneiden wollen, so müssen wir das mit absoluten Positionsangaben machen. Die Ausgabe von ps huax sieht ja etwa so aus:
at 172 0.0 0.4 892 448 ? S 10:09 0:00 /usr/sbin/atd bin 128 0.0 0.3 816 360 ? S 10:09 0:00 /sbin/portmap ...Die ProzeßIDs stehen also von Zeichen 9 bis 14. Um genau diese Spalte auszuschneiden schreiben wir also:
ps huax | cut -c9-14So bietet uns cut also die Möglichkeit, jeden beliebigen Teil einer Zeile auszuschneiden und auf die Standard-Ausgabe zu schreiben. Das ist natürlich hervorragend geeignet, um in Pipes weiterverarbeitet zu werden. Die genaue Beschreibung entnehmen Sie wieder der cut-Handbuchseite
Die genaue Beschreibung ist der expand-Handbuchseite zu entnehmen.
Die genaue Beschreibung ist der unexpand-Handbuchseite zu entnehmen.
Die genaue Beschreibung ist der fmt-Handbuchseite zu entnehmen.
Durch Kommandozeilenparameter kann bestimmt werden, wieviele Zeilen oder Bytes vom Anfang der Datei ausgegeben werden sollen. Dazu wird die gewünschte Anzahl Zeilen einfach mit einem Bindestrich versehen an den Befehl angehängt.
Die genaue Beschreibung ist der head-Handbuchseite zu entnehmen.
In Kombination mit head können damit beliebige Teile einer Datei ausgeschnitten werden. Wollen wir z.B. die Zeilen 7-12 der Datei versuch.txt, so können wir zuerst mit head die ersten 12 Zeilen der Datei auschneiden und uns dann daraus die letzten 6 Zeilen mit tail entnehmen. Elegant wird das in einer Pipe:
cat versuch.txt | head -12l | tail -6ltail hat noch den speziellen Parameter -f, der es anweist, nicht nach der Ausgabe der letzten 10 Zeilen abzubrechen, sondern zu warten, ob die Datei noch weiter wächst und die dann angehängten Zeilen ebenfalls auszugeben. Wollen wir so etwa die Meldungen des Syslog-Daemon ständig überwachen, so schreiben wir:
tail -f /var/log/messagesSolange wir tail nicht mit Strg-C abbrechen, wird es nun die Datei /var/log/messages dauernd überwachen und jede neue Zeile auf dem Bildschirm anzeigen. Wir können also der Datei "beim Wachsen zusehen".
Die genaue Beschreibung ist der tail-Handbuchseite zu entnehmen.
Die Schlüsselfelder sind - wenn nicht anders angegeben - durch Leerzeichen voneinander getrennt. Führende Leerzeichen werden ignoriert. Wenn nicht anders angegeben, ist das erste Feld einer jeden Zeile Schlüsselfeld. Die Ausgabefelder sind ebenfalls durch Leerzeichen voneinander getrennt. Die Ausgabe besteht aus dem Schlüsselfeld, gefolgt von den übrigen Feldern der Datei1 und schließlich aller Felder der passenden Zeilen von Datei2 ohne das Schlüsselfeld.
Damit können verschiedene Dateien nach inhaltlichen Kriterien zusammengefügt werden. Nehmen wir ein Beispiel:
Die Datei Adressen.txt beinhaltet Zeilen wie die folgenden:
... Huber Peter Schillerstr. 23 54321 Musterhausen Maier Hans Goethestr. 3 12345 Musterstadt Schmidt Stefan Kleistweg 34 55555 Musterhofen ...Die Datei Jobs.txt enthält jetzt etwa
Huber Geschäftsführer Kohler Fensterputzer Schmidt AufzugführerWenn wir jetzt beide Dateien mit dem Befehl
join Adressen.txt Jobs.txtmiteinander verknüpfen, so werden nur die Zeilen miteinander verbunden, die gemeinsame Schlüsselfelder haben. Voreingestellt ist das erste Feld, also der Name. Das Ergebnis wäre:
Huber Peter Schillerstr. 23 54321 Musterhausen Geschäftsführer Schmidt Stefan Kleistweg 34 55555 Musterhofen AufzugführerDie genaue Beschreibung ist der join-Handbuchseite zu entnehmen.
Die Nummerierung beginnt auf jeder Seite neu. Mehrere Dateien werden als ein einziges Dokument betrachtet, und die Zeilennummer nicht zurückgesetzt.
Der Kopfteil wird durch eine Zeile eingeleitet, die nur die Zeichenkette \:\:\: enthält. Der Körper wird entsprechend durch \:\: und der Fuß durch \: eingeleitet. In der Ausgabe werden diese Zeilen als Leerzeilen ausgegeben.
Die genaue Beschreibung ist der nl-Handbuchseite zu entnehmen.
Die genaue Beschreibung ist der od-Handbuchseite zu entnehmen.
Damit können also einzelne Dateien, die Spalten enthalten, die etwa von cut erzeugt wurden, wieder zu einer Datei zusammengesetzt werden. Nehmen wir ein simples Beispiel:
Wir wollen eine Datei erstellen, in der in der ersten Spalte die UserID, in der zweiten der Username steht. Die Datei soll alle User des Systems enthalten. Wir können das nicht allein mit cut erledigen, weil ja in /etc/passwd zuerst der Username und erst im 3. Feld die UserID steht. Zunächst erzeugen wir also zwei Dateien, die jeweils nur eine Spalte der /etc/passwd beinhalten, dann fügen wir diese beiden Dateien umgekehrt wieder zusammen:
cut -d: -f1 /etc/passwd > Datei1 cut -d: -f3 /etc/passwd > Datei2 paste -d: Datei2 Datei1 > Datei3Im Gegensatz zu join (siehe oben) werden die Zeilen der angegebenen Dateien ohne inhaltliches Kriterium miteinander verknüpft. Die genaue Beschreibung ist der paste-Handbuchseite zu entnehmen.
Immerhin bietet pr auch Features wie Spaltensatz, Seitennummerierung und Kopfzeilen, genaueres siehe bei der pr-Handbuchseite
Die kleineren Zieldateien heißen standardmäßig xaa, xab, xac, ..., wobei - falls die Buchstaben nicht ausreichen - auch mehrere Buchstaben verwendet werden (xaaaa, xaaab,...). Weil das ein wenig unhandlich ist, kann man dem split-Programm ein Präfix mitgeben, das dann das x ersetzt.
Um also z.B. eine Datei netscape.tgz mit ca 13 MByte in Dateien der Größe 1 MByte aufzuteilen, um sie auf Disketten verteilen zu können, schreiben wir:
split -b 1m netscape.tgzAls Ergebnis bekommen wir jetzt die Dateien xaa, xab, xac, ... Das ist verwirrend - daher benutzen wir eben das Präfix:
split -b 1m netscape.tgz netscape_Jetzt bekommen wir die Dateien netscape_aa, netscape_ab, ...
Um diese Dateien wieder zusammenzubauen benutzen wir einfach das cat-Programm. wir könnten so also schreiben:
cat netscape_aa netscape_ab netscape_ac netscape_ad netscape_ae > netscape.tgzDas ist zugegebenerweise etwas unhandlich, aber jetzt kommt der Vorteil ins Spiel, daß die Shell alphabetisch ihre Ausgaben sortiert. Weil die aa, ab, ac ... Aufteilung streng alphabetisch ist, können wir auch viel einfacher schreiben:
cat netscape_* > netscape.tgzDie genaue Beschreibung ist der split-Handbuchseite zu entnehmen.
Das klingt auf den ersten Blick trivial, wird aber sehr häufig gebraucht, um Dateien in eine Pipe oder auf ein Gerät zu schicken:
cat datei.txt > /dev/tty10Schickt die Datei datei.txt statt auf die Standard-Ausgabe in die Gerätedatei /dev/tty10 und damit auf das Terminal 10.
Außerdem können mit cat mehrere Dateien zu einer zusammengefügt werden, indem die Ausgabe wieder in eine Datei umgeleitet wird:
cat teil1.txt teil2.txt teil3.txt > gesamt.txtMit Optionsschaltern kann cat auch dazu gebracht werden, mehrere aufeinanderfolgende Leerzeilen zu einer Leerzeile zu reduzieren oder Zeilen in der Ausgabe zu nummerieren.
Die genaue Beschreibung ist der cat-Handbuchseite zu entnehmen.
Die genaue Beschreibung ist der tac-Handbuchseite zu entnehmen.
Die Angabe der zu übersetzenden Zeichen erfolgt dabei in sogenannten Mengen. Eine Menge ist einfach eine Zeichenkette aus Buchstaben. Um z.B. in einer Datei alle vorkommenden a,b und x in A,B und X zu verwandeln, benutzen wir die Mengen "abx" und "ABX".
tr ist ein reiner Filter, d.h., das Programm kann ausschließlich in Pipes verwendet werden. Wenn wir also die Datei Test.txt übersetzen wollen, so müssen wir schreiben:
cat Test.txt | tr abx ABX > ErgebnisZugegebenermaßen ein unsinniges Beispiel. tr erlaubt es aber auch, Steuerzeichen und andere undruckbare Zeichen in den Mengen zu verwenden, indem ihr Oktalwert angegeben wird. Dazu muß dem Wert ein Backslash vorangestellt werden. Hier sind dann aber auch Anführungszeichen nötig, sonst würde die Shell uns den Backslash weginterpretieren.
Außerdem bietet tr mehrere bereits vordefinierte Mengen, wie etwa alle Großbuchstaben und alle Kleinbuchstaben. So können wir eine Datei z.B. in Großbuchstaben verwandeln indem wir schreiben:
cat Test.txt | tr [:lower:] [:upper:] > ErgebnisDie genaue Beschreibung ist der tr-Handbuchseite zu entnehmen.
Ohne Parameter aufgerufen gibt wc alle drei Angaben aus, in der Reihenfolge Zeilen, Wörter, Zeichen. wc kennt aber auch Parameter, die es veranlassen nur die Zeilen, Wörter oder Zeichen zu zählen. Es gibt diese Parameter jeweils in einer langen und kurzen Form, aber auch jeweils leicht zu merken und zu verstehen:
Die genaue Beschreibung ist der wc-Handbuchseite zu entnehmen.