Beschreibung: Prüfungskandidaten sollten in der Lage sein, Dateien und Textdaten mittels regulärer Ausdrücke zu bearbeiten. Dieses Lernziel beinhaltet das Erzeugen einfacherer regulärer Ausdrücke mit verschiedenen Elementen. Ebenfalls enthalten ist die Verwendung von Regex-Werkzeugen zum Durchführen von Suchen über ein Dateisystem oder Dateiinhalte.
Die wichtigsten Dateien, Bezeichnungen und Anwendungen:
Die unterschiedlichsten Programme unter Linux können mit regulären Ausdrücken umgehen, allerdings unterscheiden sie sich manchmal im Detail, in der Interpretation. Es gibt aber eine gemeinsame Grundmenge von Ausdrücken, die von allen Programmen verstanden werden.
Die LPI-101-Prüfung verlangt nur das Wissen um einfache reguläre Ausdrücke, die die folgenden Elemente enthalten dürfen:
Ausdruck | Bedeutung |
---|---|
c | Ein einzelner Buchstabe passt auf sich selbst. |
. | Ein Punkt steht für genau einen beliebigen Buchstaben, außer das Zeilenende. |
\? | Das dem Operator \? voranstehende Zeichen null oder einmal. |
* | >Das dem Operator * voranstehende Zeichen null mal oder öfter. |
\+ | Das dem Operator \+ voranstehende Zeichen ein mal oder öfter. |
^ | Das Caret (^) bedeutet Zeilenanfang. |
$ | Das Dollarzeichen ($) bedeutet Zeilenende. |
\< | Bedeutet Wortanfang. |
\> | Bedeutet Wortende. |
[Buchstaben] | Ein Buchstabe aus der Menge. |
[^Buchstaben] | Ein Buchstabe, der NICHT in der Menge steht. |
\(...\) | Zusammenfassung eines Ausdrucks. Wichtig zum Ersetzen. |
\| | Ein logisches ODER mit dem verschiedene Ausdrücke verknüpft werden können. |
\ | Jedes Zeichen nach dem Backslash verliert seine Sonderbedeutung. |
Mit Hilfe dieser Ausdrücke sind sehr komplexe Suchmuster möglich, nehmen wir ein Beispiel:
Wir haben eine Datei mit Namen und wir wollen alle Formen von Maier (Maier, Mayer, Meier, Meyer, Mayr) ansprechen. Der reguläre Ausdruck würde nun lauten:
M[ae][iy]e\?rWir suchen also ein Wort, das mit einem M beginnt, danach entweder ein a oder ein e vorweist. Dem folgt entweder ein i oder ein y. Dann kommt ein oder kein e, gefolgt vom Buchstaben r.
Wichtig ist zu wissen, daß die einzelnen Ausdrücke auch kombinierbar sind. So bedeutet etwa .* eine Folge von beliebigen Zeichen, auch die leere Folge. Warum? Ganz einfach. Der Punkt meint ein beliebiges Zeichen, das Sternchen meint das dem Sternchen vorangehende Zeichen belibig oft, auch Null mal. In Kombination wird daraus eben die beliebige Folge beliebiger Zeichen.
Zu beachten ist, daß diese Suchmuster viele Zeichen enthalten, die von der Shell interpretiert würden. Wenn wir also ein solches Muster auf der Kommandozeile eingeben, dann müssen wir es in Anführungszeichen setzen.
Aber genug der Theorie, jetzt folgen die zwei Anwendungen, mit denen wir diese Ausdrücke nutzen können:
Damit ist es sowohl möglich, bestimmte Dateien zu durchsuchen, als auch die Ausgabe anderer Programme. Im einfachsten Fall durchsucht grep die Dateien nur nach einem festen Suchbegriff. Wenn Sie z.B. alle Useraccounts sehen wollen, die als Startshell die bash haben, könnten Sie das mit grep ganz leicht erledigen:
grep bash /etc/passwdDas heißt also, die Datei /etc/passwd wird nach dem Auftreten des Begriffs "bash" durchsucht und alle Zeilen, die den Begriff enthalten werden ausgegeben. Wenn mehrere Dateien durchsucht werden sollen, dann gibt grep in der Ausgabe auch noch den Dateinamen der Datei aus, in der der Suchbegriff gefunden wurde.
Wenn grep einen Datenstrom durchsuchen soll, so wird ihm einfach kein Dateiname mitgegeben. Ein Beispiel: Wir wollen alle Prozesse des Users "hans" aufgelistet bekommen. Der Befehl "ps uax" listet uns alle laufenden Prozesse samt ihrer Eigentümer auf. Der Befehl
ps uax | grep hansfiltert die Ausgabe des ps uax Befehls durch grep und gibt nur die Zeilen aus, die den Begriff "hans" enthalten. Allerdings werden wir hier auch noch die Zeile angezeigt bekommen, die den Prozess "grep hans" beschreibt. Um das zu vermeiden, bedienen wir uns der regulären Ausdrücke:
ps uax | grep "^hans"Das "^" Zeichen steht in einem regulären Ausdruck für den Zeilenanfang. Also suchen wir jetzt nach dem Auftauchen des Wortes "hans" am Zeilenanfang. Jetzt haben wir tatsächlich nur die Prozesse des Users hans.
Ein wichtiger Parameter von grep ist das -v. Mit dieser Kommandozeilenoption gibt grep nur die Zeilen aus, die nicht den Suchbegriff enthalten.
Anstatt eines einfachen Suchbegriffs können wir natürlich auch mit komplexen regulären Ausdrücken suchen. Um etwa aus einer Datei mit Adressangaben alle Adressen aller Formen des Namens Maier zu suchen, könnten wir schreiben:
grep "[Mm][ae][iy]e\?r" Adressen.txtBitte beachten Sie die Anführungszeichen. Sie verhindern, daß die Shell selbst versucht, die eckigen Klammerm und das Fragezeichen als Wildcard zu interpretieren. Grundsätzlich ist es von Vorteil, wenn Sie den Suchbegriff in solche Anführungszeichen setzen, sobald er mehr als nur Buchstaben und Zahlen beinhaltet.
Dieser Editor ist dazu entworfen, einen Datenstrom oder eine Datei automatisch zu bearbeiten. Dazu werden bestimmte Befehle, die auf diese Datei oder diesen Datenstrom anzuwenden sind, entweder in einer Datei formuliert oder gleich auf der Kommandozeile miteingetragen. Der Stream-Editor bearbeitet dann die Datei oder den Datenstrom zeilenweise und führt die jeweiligen Befehle darauf aus. Das Ergebnis wird dann wiederum auf die Standard-Ausgabe geschrieben. Wir haben das schon auf der Seite über die Textfilter besprochen.
Die mit Abstand häufigste Anwendung dieses Stream-Editors ist das Suchen und Ersetzen mit regulären Ausdrücken. Diese Vorgehensweise soll hier eingehend beschrieben werden.
Ein sed-Kommando ist immer in einen Adressbereich und einen Befehl aufgeteilt. Das Adressfeld kann dabei folgende Werte aufnehmen:
Wird bei sed der Adressteil weggelassen, so wird jede Zeile des Datenstroms bearbeitet, es wird also die Adresse 1,$ angenommen.
Der Befehl zum Suchen und Ersetzen für sed ist das s, das wie folgt angewandt werden muß:
s/Suchbegriff/Ersetzung/[Optionen]Die Angabe der Optionen ist optional (daher die eckigen Klammern), der abschließende Slash nach dem Ersetzungsteil ist aber zwingend, auch wenn keine Optionen angegeben werden sollen.
Als Optionen stehen zur Verfügung:
Im einfachsten Fall können wir also z.B. das Auftreten des Wortes "Huber" in "Herr Huber" mit dem folgenden Befehl ersetzen:
s/Huber/Herr Huber/gWie wird das nun angewandt? Entweder, wir geben diesen Befehl gleich auf der Kommandozeile ein (mit der Option -e, dann würde das etwa folgendermaßen aussehen:
cat Datei.txt | sed -e "s/Huber/Herr Huber/g" > Datei2.txtoder einfacher
sed -e "s/Huber/Herr Huber/g" Datei.txt > Datei2.txtDer Editorbefehl wurde hier in Anführungszeichen gesetzt, weil er ein Leerzeichen enthält. Wie schon bei grep ist es grundsätzlich zu empfehlen, diese Konstruktion in Anführungszeichen zu setzen um die Shell davon abzuhalten, Sonderzeichen zu interpretieren.
Was hat unser Befehl jetzt bewirkt? Jedes Vorkommen des Wortes "Huber" in der Datei Datei.txt wurde in "Herr Huber" verwandelt. Die gesamte Datei mit den Änderungen wurde in die Datei Datei2.txt geschrieben.
Wir hätten den Befehl aber auch in eine separate Datei (nennen wir sie mal Befehle) schreiben können. Das macht insbesondere dann Sinn, wenn es sich um mehrere Befehle handelt, oder wir die Ersetzung immer wieder brauchen werden. Dann hätte der sed-Aufruf einfach statt der Option -e ein -f enthalten, gefolgt vom Namen der Befehlsdatei:
sed -f Befehle Datei.txt > Datei2.txtDie eigentliche Stärke dieses Suchen und Ersetzen liegt aber natürlich wieder in der Angabe von regulären Ausdrücken. Es können hier beliebige Ausdrücke verwendet werden, wie sie oben beschrieben sind. Als besondere Möglichkeit sei hier noch auf die Klammerung mit der Konstruktion \(...\) verwiesen. Auf jedes Element, das im Suchen-Teil derart geklammert ist, kann im Ersetzen-Teil wieder zugegriffen werden. Dazu muß nur eine Nummer n mit vorgestelltem Backslash (\) angegeben werden. Das meint die n-te Klammer. Ein Beispiel:
Wir haben eine Datei Namen.txt mit folgendem Inhalt:
Hans Müller Peter Schmidt Michael Huber Gabi Maier Thomas GruberWir wollen jetzt die Namen in der Form Nachname, Vorname haben. Kein Problem mit sed. Wir schreiben
sed -e "s/\(.*\) \(.*\)/\2, \1/" Namen.txt > Namen2.txtSchon steht in der Datei Namen2.txt
Müller, Hans Schmidt, Peter Huber, Michael Maier, Gabi Gruber, ThomasWas ist passiert? Schauen wir uns den sed-Befehl einmal genauer an. Der reguläre Ausdruck .* steht für eine beliebige Zeichenfolge beliebiger Länge. Also können wir die zwei Namen (Vor- und Nachname) auch als .* .* angeben. Also zwei beliebige Zeichenfolgen, getrennt durch ein Leerzeichen. Jetzt klammern wir die beiden Konstrukte jeweils mit \(...\) ein. So entsteht zweimal der Ausdruck \(.*\). Auf jeden dieser geklammerten Ausdrücke können wir jetzt im Ersetzen-Teil des sed-Befehls wieder zugreifen, mit \1 für den ersten gefundenen Ausdruck und \2 für den zweiten.
Dadurch entsteht folgende Zuordnung, am Beispiel der ersten Zeile:
\(.*\)\(.*\)
| Hans | Müller
| \1 | \2
| |
Im Ersetzen-Teil schreiben wir einfach \2, \1, das wird dann eben ersetzt durch den Inhalt der zweiten Klammer, gefolgt von einem Komma, einem Leerzeichen und dem Inhalt der ersten Klammer. Also in unserem Beispiel durch Müller, Hans.