Reguläre Ausdrücke

Die Suche nach Zeichenketten ist unter Unix erheblich komfortabler und komplexer implementiert als zum Beispiel unter DOS. Die üblichen Werkzeuge wie sed, awk, perl, vi etc. verwenden keine herkömmlichen Algorithmen, mit denen einfache Zeichenketten gesucht werden. Stattdessen verarbeiten ihre Routinen sogenannte reguläre Ausdrücke und sind dadurch erheblich mächtiger als eine vergleichbare Funktion unter DOS.

Der Begriff "Regulärer Ausdruck" stammt von dem Sprachwissenschaftler Noam Chomsky und wird in der Informatik verwendet. Er bezeichnet ein Schema zum Erzeugen von Zeichenketten nach bestimmten Regeln. Mit einem regulären Ausdruck kann eine Menge von Zeichenketten erzeugt werden (die Sprache). Genauso kann überprüft werden, ob eine Zeichenkette in der dieser Menge liegt. Letzteres Verfahren wird auch als Pattern Matching (engl. Mustererkennung) bezeichnet.

Aufbau von regulären Ausdrücken

Die leere Zeichenkette ist ein regulärer Ausdruck. Die Folge "abc" ebenfalls. Er beschreibt die hintereinander geschriebenen drei Buchstaben "a", "b" und "c".

Sind a und b reguläre Ausdrücke, so können sie wie folgt zu komplexeren Ausdrücken zusammengesetzt werden:

(a) beschreibt weiterhin den regulären Ausdruck a. Mit runden Klammern werden Ausdrücke gruppiert. Dadurch können nachfolgende Operatoren sowohl auf einzelne Zeichen als auch auf bereits reguläre Ausdrücke angewendet werden.
a? steht für das null- oder einfache Auftreten von a.
a* beschreibt die Häufigkeit von a. Der Ausdruck kann keinmal oder beliebig oft vorkommen.
a+ Der reguläre Ausdruck a muß mindestens einmal, kann aber beliebig oft vorkommen.
a|b steht für eine ODER-Verknüpfung der beiden Ausdrücke. Damit werden Zeichenketten gefunden, die auf a oder auf b passen.
ab entspricht der UND-Verknüpfung von zwei regulären Ausdrücken. Wenn z.B. a für "who" und b für "(was|is)" steht, dann erzeugt ab die beiden Wörter "whois" und "whowas" bzw. erkennt die beiden Wörter "whois" und "whowas".

Zur Bildung von regulären Ausdrücken können in den Unix-Werkzeugen zusätzlich folgende Erweiterungen benutzt werden. Sie ergeben für diese erneut reguläre Ausdrücke.

[abc] steht für eines der Zeichen "a", "b" oder "c". (*)
[^xyz] paßt auf jedes Zeichen, außer auf "x", "y" und "z". (*)
. paßt auf jedes Zeichen
\0nn entspricht dem Zeichen, welches den Oktalwert nn hat.
\xnn repräsentiert das Zeichen, das den Hexadezimalwert nn hat.

Unix-Werkzeuge verwenden zusätzlich noch folgende Erweiterungen. Sie können jedoch nur auf den gesamten regulären Ausdruck angewendet werden:

^a Der reguläre Ausdruck a muß am Zeilenanfang stehen.
a$ Der reguläre Ausdruck a muß am Ende einer Zeile auftreten.
Meistens werden die Ausdrücke in Schrägstriche eingefaßt, teilweise können auch beliebige andere, jedoch gleiche, Zeichen verwendet werden (z.B. beim vi und sed). Durch die Schrägstriche erhalten sie das für Unix typische Aussehen.

Da zur Beschreibung der regulären Ausdrücke verschiedene Kontrollzeichen benötigt werden, können diese nicht mehr in den Ausdrücken selbst vorkommen. Aus diesem Grund müssen sie in einem solchen Fall geschützt dargestellt werden. Ihnen wird ein Backslash vorangestellt. Gleiches gilt für ähnliche Sonderzeichen in der Shell.

Der in Schrägstrichen eingefaßte reguläre Ausdruck

   /Th?om(as)? (Ch|K)rist(ia|e)nss?s[eo]n/
  
paßt zum Beispiel auf Thomas, Thom oder Tom Christianssen, Christiansson, Christenssen, Christensson, mit K oder Ch sowie mit einem oder zwei s im Nachnamen.

Verschiedene Programme haben ihr Verständnis von regulären Ausdrücken noch erweitert. So ist es z.B. beim Emacs, sed und perl möglich Suchen-und-Ersetzen mit regulären Ausdrücken durchzuführen und Teile des gefundenen Ausdruckes in speziellen Variablen zwischenzuspeichern.

Zudem ist es teilweise möglich, die Unterscheidung von Groß- und Kleinschreibung auszuschalten. Bei perl ist der Autor sogar soweit gegangen, daß spezielle Meta-Zeichen definiert sind, um bestimmte Gruppen von Zeichen wie Buchstaben, Leerzeichen, Zahlen etc. leichter angeben zu können.

Wildcard Matching

Neben dieser komplexen Methode Zeichenketten zu vergleichen, existiert noch eine ein zweite. Dabei werden Wildcards, ähnlich wie unter DOS, verwendet. Neben den mit (*) gekennzeichneten Regeln von oben gelten zusätzlich folgende:

? paßt auf ein beliebiges Zeichen.
* entspricht beliebig vielen Zeichen, z.B. auch keinem.
Diese Implementierung ist im Newssystem INN, welches an anderer Stelle kurz erwähnt wird, für die Erkennung von Newsgruppen eingesetzt.

Auf Shellebene (z.B. bei Verwendung der bash) wird diese einfachere Methode verwendet, um Dateinamen auszuwählen. Allerdings wird sie erneut um folgende Fähigkeit ergänzt.

{abc,xyz,etc} paßt auf den regulären Ausdruck (abc|xyz|etc)
Der Befehl

   ls -l /usr/bin/{,s,proc}mail*
  
listet z.B.

   /usr/bin/mail
   /usr/bin/smail
   /usr/bin/smail.old
   /usr/bin/procmail
   /usr/bin/mailto
  
auf und

   ls -l /usr/bin/*mail
  
hingegen

   /usr/bin/mail
   /usr/bin/smail
   /usr/bin/rmail
   /usr/bin/procmail
   /usr/bin/sendmail
  

I/O-Umleitungen

In einer Bourne Shell existieren noch eine Reihe zusätzlicher Sonderzeichen, die ggf. ebenfalls mit einem vorangestelltem Backslash geschützt werden müssen.

> Leitet die Ausgabe des Befehls in eine Datei um. Eine schon bestehende wird überschrieben.
>> s.o., allerdings wird die Ausgabe an eine bestehende angehängt, sofern sie existiert.
2> Leitet die Fehlerausgabe in eine Datei um. Viele Programme unterscheiden zwischen normaler und Fehlerausgabe, die normalerweise ebenfalls auf dem Terminal ausgegeben würde.
2>&1 Hier wird die Fehlerausgabe auf den normalen Ausgabestrom umgeleitet. Wird dieses nach einer normalen Umleitung geschrieben, dann landen die Fehlermeldungen in der gleichen Datei wie die normalen Ausgaben.
< Nimmt die Eingabe für den Befehl aus der angegebenen Datei anstatt von der Tastatur
| Die Ausgabe des linksstehenden Befehls wird als Eingabe für den rechts vom Pipezeichen stehendenden Befehl benutzt.

Martin Schulze

Quelle: Linux-Special vom Toolbox-Verlag '97


© Joey, 26 Dec '97