Skip to content

7 Reguläre Ausdrücke

7 Reguläre Ausdrücke

Lernziele

  • Einfache und erweiterte reguläre Ausdrücke verstehen und formulieren können

  • Das Kommando grep und seine Varianten fgrep und egrep kennen

Vorkenntnisse

  • Grundlegende Kenntnisse über Linux und Linux-Kommandos (etwa aus den vorhergehenden Kapiteln).

  • Umgang mit Dateien und Verzeichnissen (siehe Kapitel 6)

  • Umgang mit einem Texteditor (siehe Kapitel 3)

7.1 Reguläre Ausdrücke: Die Grundlagen

Viele Linux-Kommandos dienen im weitesten Sinne zur Textbearbeitung. Dabei taucht immer wieder die Form „tue 𝑥𝑦𝑧 für alle Zeilen, die wie folgt aussehen” auf. Ein sehr mächtiges Mittel zur Beschreibung von Textstücken – meist Zeilen in Dateien – sind „reguläre Ausdrücke”1. Auf den ersten Blick ähneln sie den Suchmustern der Shell (Abschnitt 6.3), aber sie funktionieren anders und bieten mehr Möglichkeiten.

Reguläre Ausdrücke werden gerne „rekursiv” aus Bausteinen aufgebaut, die selbst als reguläre Ausdrücke gelten. Die einfachsten regulären Ausdrücke sind einzelne Buchstaben, Ziffern und viele andere Zeichen des üblichen Zeichenvorrats. „a” wäre also ein regulärer Ausdruck, der auf das Zeichen „a” passt, während der reguläre Ausdruck „abc” auf die Zeichenkette „abc” passt. Ähnlich wie bei Shell-Suchmustern gibt es die Möglichkeit, Zeichenklassen zu definieren: Der reguläre Ausdruck „[a-e]” passt auf genau eines der Zeichen „a” bis „e” und „a[xy]b” passt entweder auf „axb” oder „ayb”. Wie bei der Shell können Bereiche gebildet und zusammengefasst werden – „[A-Za-z]” passt auf alle Groß- und Kleinbuchstaben (ohne Umlaute) –, nur die Komplementbildung funktioniert etwas anders: „[^abc]” passt auf alle Zeichen außer „a”, „b” und „c”. (Bei der Shell hieß das „[!abc]”.) Der Punkt „.” entspricht dem Fragezeichen in Shell-Suchmustern und steht für ein einziges beliebiges Zeichen – ausgenommen davon ist nur der Zeilentrenner „\n”: „a.c” passt also auf „abc”, „a/c” und so weiter, aber nicht auf die mehrzeilige Konstruktion.

a
c

Der Grund dafür ist, dass die meisten Programme zeilenorientiert vorgehen und „zeilenübergreifende” Konstruktionen schwieriger zu verarbeiten wären. (Was nicht heißen soll, dass es nicht manchmal praktisch wäre, das zu können.)

Während Shellsuchmuster immer vom Anfang eines Pfadnamens aus passen müssen, reicht es bei Programmen, die Zeilen aufgrund von regulären Ausdrücken auswählen, meist aus, wenn der reguläre Ausdruck irgendwo in einer Zeile passt. Allerdings können Sie diese Freizügigkeit einschränken: Ein regulärer Ausdruck, der mit dem Zirkumflex („^”) anfängt, passt nur am Zeilenanfang und ein regulärer Ausdruck, der mit dem Dollarzeichen („$”) aufhört, entsprechend nur am Zeilenende. Der Zeilentrenner am Ende jeder Zeile wird ignoriert, sodass Sie „xyz$” schreiben können, um alle Zeilen auszuwählen, die mit „xyz” enden, und nicht „xyz\n$” angeben müssen.

💡 Streng genommen passen „^” und „$” auf gedachte „unsichtbare” Zeichen am Zeilenanfang bzw. unmittelbar vor dem Zeilentrenner am Zeilenende.

Mit dem Stern () können Sie angeben, dass der davorstehende Ausdruck beliebig oft wiederholt werden kann (auch gar nicht). Der Stern selbst steht nicht für irgendwelche Zeichen in der Eingabe, sondern modifiziert nur das davorstehende Zeichen. Das Shellsuchmuster „a.txt” entspricht somit dem regulären Ausdruck „^a.*.txt$” (denken Sie an die „Verankerung” des Ausdrucks am Anfang und Ende der Eingabe und daran, dass ein einzelner Punkt auf alle Zeichen passt).

Wiederholung hat Vorrang vor Aneinanderreihung. „ab*” ist ein einzelnes „a”, gefolgt von beliebig vielen „b” (auch keinem), nicht eine beliebig häufige Wiederholung von „ab”.

7.2 Reguläre Ausdrücke: Extras

Die Beschreibung aus dem vorherigen Abschnitt gilt für praktisch alle Linux-Programme, die reguläre Ausdrücke verarbeiten. Diverse Programme unterstützen jedoch auch verschiedene Erweiterungen, die entweder Schreibvereinfachungen bieten oder tatsächlich zusätzliche Funktionen ermöglichen. Die „Krone der Schöpfung” sind hier die modernen Skriptsprachen wie Tcl, Perl oder Python, deren Implementierungen inzwischen weit über das hinausgehen, was reguläre Ausdrücke im Sinne der theoretischen Informatik können.

Einige gängige Erweiterungen sind:

  • Wortklammern

    Die Sequenz „\<“ passt am Anfang eines Worts, also an einer Stelle, an der ein Nichtbuchstabe auf einen Buchstaben trifft. Analog dazu passt „>” am Ende eines Worts, also an der Stelle, an der ein Buchstabe von einem Nichtbuchstaben gefolgt wird.

  • Gruppierung

    Mit Hilfe von runden Klammern (»(…)«) können Aneinanderreihungen von regulären Ausdrücken wiederholt werden: »a(bc)« passt auf ein »a«, gefolgt von beliebig vielen Wiederholungen von »bc«. Im Gegensatz dazu passt »abc« auf »ab«, gefolgt von beliebig vielen Wiederholungen von »c«.

  • Alternative

    Mit dem vertikalen Balken (»|«) können Sie eine Auswahl zwischen mehreren regulären Ausdrücken treffen:

    »Affen(brot|schwanz|kletter)baum« passt genau auf eine der Zeichenketten »Affenbrotbaum«2, »Affenschwanzbaum«3 oder »Affenkletterbaum«.

  • Optionales

    Das Fragezeichen (*) macht den vorstehenden regulären Ausdruck optional, d. h., er tritt entweder einmal auf oder gar nicht. „Boot(smann)?” passt auf „Boot” oder „Bootsmann”.

  • Mindestens einmal

    Das Pluszeichen („+“) entspricht dem Wiederholungsoperator „*“, mit dem Unterschied, dass der vorstehende Ausdruck mindestens einmal auftreten muss, also nicht ganz entfallen darf.

  • Bestimmte Anzahl von Wiederholungen

    In geschweiften Klammern können Sie eine Mindest- und eine Maximalanzahl von Wiederholungen angeben: „ab{2,4}” passt auf „abb”, „abbb” und „abbbb”, aber nicht auf „ab” oder „abbbbb”. Sie können sowohl die Mindest- als auch die Maximalanzahl weglassen. Fehlt die Mindestanzahl, wird 0 angenommen, fehlt die Maximalanzahl, wird „unendlich” angenommen.

  • Rückbezug

    Mit einem Ausdruck der Form „\𝑛” können Sie eine Wiederholung des Teils der Eingabe verlangen, der auf den Klammerausdruck Nr. 𝑛 im regulären Ausdruck gepasst hat. „(ab)\1” passt beispielsweise auf „abab” und wenn bei der Bearbeitung von „(ab*a)x\1” die Klammer auf „abba” passt, dann passt der gesamte Ausdruck auf „abbaxabba” (und nichts anderes). Weitere Details finden Sie in der Dokumentation zu GNU grep.

  • »Bescheidene« Vorgehensweise

    Die Operatoren „“, „+“ und „?“ sind normalerweise „gierig“, das heißt, sie versuchen, so viel der Eingabe wie möglich zu erfassen: „^a.a“ bezogen auf die Eingabe „abacada“ passt auf „abacada“, nicht auf „aba“ oder „abaca“. Es gibt aber auch „bescheidene” Versionen dieser Operatoren: „?”, „+?” und „???”, die auf so wenig der Eingabe wie möglich passen. In unserem Beispiel würde „^a.?a” auf „aba” passen. Auch die geschweiften Klammern haben möglicherweise eine bescheidene Version.

Es gibt nicht für jedes Programm Erweiterungen, die auch von diesem unterstützt werden. Tabelle 7.1 gibt einen Überblick über die wichtigsten Programme. Insbesondere die Programme Emacs, Perl und Tcl unterstützen noch zahlreiche weitere, hier nicht diskutierte Erweiterungen.

Tabelle 7.1: Unterstützung von regulären Ausdrücken

Erweiterung GNU grep GNU egrep trad. egrep vim emacs Perl Tcl
Wortklammern * * * *1 *1 *4 *4
Gruppierung *1 * * *1 *1 * *
Alternative *1 * * *2 *1 * *
Optionales *1 * * *3 * * *
mind. einmal *1 * * *1 * * *
Anzahl *1 * *1 *1 * *
Rückbezug * * * * *
Bescheiden *4 * * *

*: wird unterstützt; ∘: wird nicht unterstützt

Anmerkungen:

  1. Wird durch einen vorgesetzten Rückstrich („\”) angesprochen, also z. B. „ab+” statt „ab+”.
  2. Es werden keine Klammern benötigt, da sich die Alternativen immer auf den kompletten Ausdruck beziehen.
  3. Es wird »\=« statt »?« benutzt.
  4. Es wird eine ganz andere Syntax verwendet (siehe Dokumentation).

Tabelle 7.2: Optionen für grep (Auswahl)

Option Wirkung
-c (count) Liefert nur die Anzahl der passenden Zeilen
-i (ignore) Klein und Großbuchstaben werden nicht unterschieden
-l (list) Statt kompletter Zeilen werden nur Dateinamen ausgegeben
-n (number) Die Zeilennummer der gefundenen Zeilen in der Eingabe wird mit ausgegeben
-r (recursive) Auch Dateien in Unterverzeichnissen usw. mit durchsuchen
-v (invert) Nur Zeilen, die das Muster nicht enthalten, werden ausgegeben

7.3 Dateien nach Textteilen durchsuchen – grep

Grep ist vielleicht eines der wichtigsten Linux-Programme, die reguläre Ausdrücke verwenden. Es durchsucht eine oder mehrere Dateien nach Zeilen, die einem angegebenen regulären Ausdruck entsprechen. Passende Zeilen werden ausgegeben, nicht passende verworfen.

Von Grep existieren zwei Ableger: Das abgespeckte Fgrep (engl. fixed, „fest vorgegeben”) erlaubt traditionell keine regulären Ausdrücke, sondern nur feste Zeichenketten, ist dafür aber sehr flott. Zusätzliche Möglichkeiten bietet egrep (engl. extended, „erweitert”), der jedoch recht langsam arbeitet und viel Speicherkapazität benötigt.

💡 Früher haben diese Anmerkungen tatsächlich im Großen und Ganzen gestimmt. Insbesondere verwendeten grep und egrep völlig verschiedene Verfahren zur Auswertung der regulären Ausdrücke, die je nach deren Gestalt und Umfang sowie der Größe der Eingabe zu ganz unterschiedlichen Laufzeitergebnissen führen konnten. Bei der unter Linux üblichen grep-Implementierung aus dem GNU-Projekt sind jedoch alle drei Varianten dasselbe Programm und unterscheiden sich vor allem in der Syntax dessen, wonach gesucht werden soll.

Die Syntax von grep erfordert mindestens die Angabe des regulären Ausdrucks, nach dem gesucht werden soll. Darauf folgt der Name der Textdatei (oder die Namen der Textdateien), die nach diesem Ausdruck durchsucht werden soll(en). Wurde kein Dateiname angegeben, bezieht sich grep auf die Standard-Eingabe (siehe Kapitel 8).

Der reguläre Ausdruck, nach dem die Eingabe durchsucht wird, darf neben den grundlegenden Bausteinen aus Abschnitt 7.1 auch die meisten Erweiterungen aus Abschnitt 7.2 enthalten. Die Operatoren „+”, „\?” und „{” müssen Sie bei grep jedoch mit dem Rückstrich versehen. (Bei egrep können Sie darauf verzichten.) „Bescheidene” Operatoren gibt es leider nicht.

⚠️ Damit die Sonderzeichen nicht bereits von der Shell interpretiert, sondern korrekt an grep übergeben werden, sollten Sie den regulären Ausdruck in Anführungszeichen setzen – jedenfalls, wenn er komplizierter als eine einfache Zeichenkette ist und insbesondere, wenn er einem Shell-Suchmuster ähnelt.

Neben dem regulären Ausdruck und gegebenenfalls Dateinamen können wie gewohnt auch verschiedene Optionen auf der Kommandozeile angegeben werden (siehe Tabelle 7.2).

Mit der Option -f (engl. file, „Datei”) können reguläre Ausdrücke aus einer Datei gelesen werden. Enthält diese Musterdatei mehrere Zeilen, wird jeweils der Inhalt einer kompletten Zeile als einzelner Ausdruck angesehen. Dies bringt bei häufig benutzten Suchoperationen eine deutliche Arbeitserleichterung mit sich.

Wie erwähnt, erlaubt fgrep keine regulären Ausdrücke, sondern nur konstante Zeichenketten als Suchobjekte, während egrep die meisten Erweiterungen für reguläre Ausdrücke bequemer verfügbar macht (siehe Tabelle 7.1).

Zum Abschluss folgen noch ein paar Beispiele zur Anwendung von grep. Die Datei frosch.txt enthält das Märchen vom Froschkönig (siehe Kapitel B). Alle Zeilen, die die Zeichenkette „Frosch” enthalten, finden Sie leicht wie folgt:

$ grep Frosch frosch.txt
Der Froschkönig oder der eiserne Heinrich
Sie sah sich um, woher die Stimme käme, da erblickte sie einen Frosch,
»Sei still und weine nicht«, antwortete der Frosch, »ich kann wohl Rat
»Was du haben willst, lieber Frosch«, sagte sie, »meine Kleider, meine
✁✁✁✁✁

Um die Zeilen zu finden, die genau das Wort „Frosch” (und nicht irgendwelche Zusammensetzungen wie „Froschkönig”) enthalten, benötigen Sie die Wortklammer-Erweiterung:

$ grep '\<Frosch\>' frosch.txt
Sie sah sich um, woher die Stimme käme, da erblickte sie einen Frosch,
»Sei still und weine nicht«, antwortete der Frosch, »ich kann wohl Rat
»Was du haben willst, lieber Frosch«, sagte sie, »meine Kleider, meine Der Frosch antwortete: »Deine Kleider, deine Perlen und Edelsteine und
✁✁✁✁✁

Es ist auch ganz einfach, alle Zeilen zu finden, die mit „Frosch” beginnen:

$ grep ^Frosch frosch.txt
Frosch mag schwätzen, was er will, der sitzt doch im Wasser bei Frosch.«
Frosch verwandelt worden war, daß er drei eiserne Bänder um sein Herz

Ein anderes Beispiel: In /usr/share/dict/words steht eine Liste englischer Wörter, die gerne als „Wörterbuch” bezeichnet4 wird. Wir interessieren uns für alle Wörter mit drei oder mehr „a”:

$ grep -n 'a.*a.*a' /usr/share/dict/words
8:aardvark 21:abaca 22:abacate
✁✁✁✁✁ … 7030 andere Wörter …
234831:zygomaticoauricularis 234832:zygomaticofacial 234834:zygomaticomaxillary

(in dieser Reihenfolge: das Erdferkel (Orycteropus afer), eine faserspendende Bananenpflanze (Musa textilis), der brasilianische Name für die Avocado (Persea sp.), ein Muskel im Gesicht sowie zwei Adjektive aus demselben medizinischen Umfeld.)

💡 Bei komplizierteren regulären Ausdrücken kann es schnell unübersichtlich werden, warum grep eine Zeile ausgibt und eine andere nicht. Etwas Abhilfe kann hier die Option --color schaffen, die die Treffer in einer Zeile farblich hervorhebt:

$ grep --color root /etc/passwd root:x:0:0:root:/root:/bin/bash

Durch den Befehl export GREP_OPTIONS="--color=auto" (in ~/.profile o. Ä.) wird die Option dauerhaft aktiviert. Der Zusatz auto bewirkt dabei, dass die Farben unterdrückt werden, sobald die Ausgabe in eine Pipeline oder Datei umgeleitet wird.

Übungen

✏️ 7.1 [2] Sind die Operatoren ? und + in regulären Ausdrücken wirklich nötig?

✏️ 7.2 [!1] Finden Sie in der Datei „frosch.txt” alle Zeilen, in denen die Wörter „Tochter” oder „Königstochter” vorkommen.

✏️ 7.3 [!2] In der Datei /etc/passwd sind die Benutzer des Rechners gespeichert (meistens jedenfalls). Jede Zeile der Datei besteht aus mehreren durch Doppelpunkte getrennten Feldern. Das letzte Feld jeder Zeile gibt die Login-Shell eines Benutzers an. Geben Sie eine grep-Kommandozeile ein, mit der Sie alle Benutzer finden können, die die Bash als Login-Shell verwenden.

✏️ 7.4 [3] Suchen Sie in /usr/share/dict/words nach allen Wörtern, die genau die fünf Vokale „a”, „e”, „i”, „o” und „u” in dieser Reihenfolge enthalten (möglicherweise mit Konsonanten davor, dazwischen oder dahinter).

✏️ 7.5 [4] Geben Sie ein Kommando an, das im „Froschkönig” alle Zeilen sucht und ausgibt, in denen ein mindestens vierbuchstabiges Wort zweimal auftritt.

7.4 Kommandos in diesem Kapitel

Kommando Beschreibung manpage
egrep Sucht in Dateien nach Zeilen mit bestimmtem Inhalt, erweiterte reguläre Ausdrücke erlaubt grep(1)
fgrep Sucht in Dateien nach Zeilen bestimmten Inhalts, keine regulären Ausdrücke erlaubt fgrep(1)
grep Sucht in Dateien nach Zeilen mit bestimmtem Inhalt grep (1)

7.5 Zusammenfassung

  • Reguläre Ausdrücke sind eine mächtige Methode, um ganze Gruppen von Zeichenketten zu beschreiben.

  • Mit grep und seinen Verwandten können Dateiinhalte nach Zeilen durchsucht werden, die auf reguläre Ausdrücke passen.


  1. Der Begriff stammt ursprünglich aus der theoretischen Informatik und beschreibt ein Verfahren zur Charakterisierung von Mengen von Zeichenketten, die aus der Verkettung von konstanten Elementen und Alternativen dieser Elemente sowie deren unbegrenzter Wiederholung bestehen. Routinen zur Erkennung regulärer Ausdrücke sind elementare Bestandteile vieler Programme, etwa von Compilern für Programmiersprachen. In der Geschichte von Unix tauchten reguläre Ausdrücke schon sehr früh auf, da die meisten frühen Unix-Entwickler einen Hintergrund in theoretischer Informatik hatten und die Idee ihnen daher nahe lag. 

  2. Adansonia digitata 

  3. Volkstümlicher Name für die Araukarie (Araucaria araucana) 

  4. Der Inhalt des Wörterbuchs kann je nach Distribution mehr oder weniger umfangreich ausfallen.