Tipp: Regular Expressions
Reguläre Ausdrücke
Um den Einsatz
von z. B. sed
effizienter zu gestalten, bedarf es der Kenntnisse über ‘Reguläre
Ausdrücke’.
Hintergründe
Viele Linux-Kommandos kennen bei Filterfunktionen nicht nur einzelne Sonderzeichen, sondern auch sogenannte ‘Reguläre Ausdrücke’ (‘Regular Expressions’), auch als ‘RegEx’ oder ‘RegExp’ abgekürzt. Ein regulärer Ausdruck ist sozusagen ein Platzhalter, der (durchaus komplexe) Gruppen von Zeichenketten repräsentiert.
Zwar gibt es verschiedene Implementierungen der RegEx, doch sind die meisten kompatibel mit den ‘Perl Compatible Regular Expressions’ (PCRE). Auch das ‘Portable Operating System Interface’ (POSIX) definiert reguläre Ausdrücke; es ist den PCRE sehr ähnlich, unterscheidet aber etwa einfache und erweiterte RegEx. Welche Art der regulären Ausdrücke und in welchem Umfang sie ein Programm unterstützt, beschreibt dessen Dokumentation.
Reguläre Ausdrücke dienen also allgemein dazu, Texte nach bestimmten, sehr frei definierbaren Mustern zu durchsuchen, um die Ergebnisse weiterverarbeiten zu können.
Grundlagen
Wie in der Shell gibt es bei den regulären Ausdrücken Zeichen, die
Sonderfunktionen haben: Der Punkt (.
) steht für ein
beliebiges Zeichen, der Zirkumflex (^
) für
den Zeilenanfang oder – innerhalb einer Zeichenklasse – für eine
Negierung und das Dollarzeichen ($
) für das
Zeilenende. Wenden wir diese Ausdrücke auf den folgenden Text (den
Schluss von Ernst Jandls Gedicht ``ottos mops’’) in einer Datei
otto.txt
an:
user@linux:~$ cat otto.txt
ottos mops kommt
ottos mops kotzt
otto: ogottogott
Zum Einsatz kommt der Befehl grep
, der die Ergebnisse einer Mustersuche zeilenweise
anzeigt:
user@linux:~$ grep ^ottos otto.txt
ottos mops kommt
ottos mops kotzt
grep
liefert zwei Zeilen des Gedichts, da diese mit ottos
beginnen.
user@linux:~$ grep tt$ otto.txt
otto: ogottogott
Nur für die letzte Zeile trifft das Muster (``zwei t am Zeilenende’’) zu.
Darüber hinaus gibt es Notationen für Zeichenklassen,
beispielsweise [:alnum:]
für
alphanumerische Zeichen, [:blank:]
für jegliche Art von
Leerzeichen oder [:upper:]
für Groß- und
[:lower:]
für Kleinbuchstaben. Auch die Angabe von
Bereichen ist möglich: [a-f]
(die Kleinbuchstaben von a
bis
f
), [0-9]
(sämtliche Ziffern) und vieles mehr.
Das folgende Kommando sucht die Zeilen, in denen der Buchstabe o
,
gefolgt von den Buchstaben zwischen i
und m
,
vorkommt.
user@linux:~$ grep o[i-m] otto.txt
ottos mops kommt
Darüber hinaus gibt es die folgenden vordefinierten Zeichenklassen:
\d
- eine Ziffer, also[0-9]
\D
- ein Zeichen, das keine Ziffer ist, also[^\d]
\w
- ein Buchstabe, eine Ziffer oder der Unterstrich, also[a-zA-Z_0-9]
und eventuell weitere Buchstaben, zum Beispiel Umlaute\W
- ein Zeichen, das weder Buchstabe noch Zahl noch Unterstrich ist, also[^\w]
\s
- Leerzeichen und die Klasse der Steuerzeichen\f
(Seitenvorschub),\n
(Zeilenumbruch),\r
(Wagenrücklauf),\t
(Tabulator) und\v
(vertikaler Tabulator)\S
- ein Zeichen, das kein Leerraum (Whitespace) ist, also[^\s]
Alle Kombinationen von regulären Ausdrücke basieren auf prinzipiell drei Operationen: ‘Alternative’, ‘Verkettung’ und ‘Wiederholung’.
Ein vertikaler Strich (das Pipezeichen |
) markiert eine
Alternative. Aber auch Zeichenklassen, eingeschlossen in eckige
Klammern ([
und ]
), weisen Alternativen aus. Mit einer
Start- und Endziffer oder Buchstaben mit einem Minus (-
)
dazwischen lassen sich innerhalb eckiger Klammern Bereiche definieren.
Auch Wiederholungen kann der Benutzer sehr fein definieren. Ein
Fragezeichen (?
) steht für einen Ausdruck, der einmal vorhanden sein
kann, aber nicht muss. Ein Asterisk (*
) steht für
beliebig oft'', was auch die Anzahl null, also
nicht vorhanden’’, einschließt. Ein Plus (+
) steht für
``mindestens einmal’’, kann also ein oder beliebig viele Vorkommen des
Ausdrucks treffen.
Geschweifte Klammern ({
und }
) lassen noch
genauere Definitionen zu: Eine so eingeschlossene Zahl fordert die
Wiederholung entsprechend oft ein. Eine Zahl gefolgt von einem Komma innerhalb der
geschweiften Klammern gibt einen Mindestwert für die Anzahl der
Wiederholungen an. Zwei Zahlen von einem Komma getrennt in geschweiften
Klammern stehen schließlich für einen fest definierten Bereich von
Wiederholungen.
Zeichen sind immer miteinander verkettet, das heißt, der Benutzer definiert die
gewünschte Reihenfolge. Doch alle anderen Operationen (zum Beispiel die
Wiederholung im vorherigen Absatz) haben dabei eine stärkere Bindung. Wer
jedoch der Verkettung eine stärkere Bindung zuweisen will, umschließt sie
mit runden Klammern (
und )
.
Will der Anwender die Zeichen [
]
(
)
{
}
|
?
+
-
*
^
$
\
.
ohne ihre Sonderbedeutung, als druckbare Zeichen,
benutzen, muss er sie ’escapen’, also der Umgebung mitteilen ``Achtung,
jetzt das Zeichen ohne Meta-Bedeutung’’. Dies geschieht mit einem
vorangestellten Backslash (\
).
Spätestens jetzt sollte deutlich geworden sein, ‘wie’ komplex, aber eben auch mächtig reguläre Ausdrücke sein können und welche Flexibilität sie dem Benutzer bei der Arbeit bieten; nicht zufällig füllt das Thema ganze Bücher. Was auf den ersten, unerfahrenen Blick überladen scheint, erweist sich in der Praxis sehr schnell als überaus hilfreich oder gar notwendig.
Stellen Sie sich einen Administrator vor, der für die Mailserver eines Internet-Providers mit Tausenden E-Mail-Adressen zuständig ist. In den Wochen zuvor gab es eine Flut von Spam-Mails, und die Aufgabe lautet nun: ``Suche in den Log-Files der vergangenen zwei Wochen alle Nachrichten, die im Betreff bestimmte Wörter enthalten, deren Absenderadresse von einer bestimmten Top-Level-Domain kommt und die über Server aus einem bestimmten Netzbereich verschickt wurden.’’
Beispiele
Aufgaben dieser Art sind – das sollte deutlich geworden sein – ohne Filter nicht zu lösen. Das Potential aus der Verbindung von Linux-Kommandos, Shell und regulären Ausdrücken lässt sich hier nur andeuten und soll vor allem zu weiteren Recherchen anregen. Hier noch einige Beispiele für funktionierende reguläre Ausdrücke, sozusagen als ``Appetitanreger’’:
abc
- die Zeichenkette ``abc’’(abc|xzy)
- die Zeichenketteabc'' oder
xyz’'[abcx-z0-9]
- eines der Zeichena'',
b’’,c'',
x’’,y'',
z’’ oder eine Ziffer^.$
- genau ein beliebiges Zeichen in der Zeile^#
- die Zeile beginnt mit einer Raute (derartige Formatierungen sind häufig als Kommentare in Shellskripten zu finden)\w+\.[a-zA-Z0-9]{2,}
- ein oder mehr Buchstaben, Ziffern oder Unterstriche, dann ein Punkt, gefolgt von mindestens zwei Buchstaben und/oder Ziffern
eine IPv4-Adresse::
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
eine gültige E-Mail-Adresse::
^((?:(?:(?:\w[\.\-\+]?)*)\w)+)\@((?:(?:(?:\w[\.\-\+]?){0,62})\w)+)\.(\w{2,6})$