Website-Suche

Einführung in grep und reguläre Ausdrücke


Objektiv

Nachdem Sie dieses Tutorial gelesen haben, sollten Sie in der Lage sein zu verstehen, wie der grep-Befehl funktioniert und wie Sie ihn mit grundlegenden und erweiterten regulären Ausdrücken verwenden.

Schwierigkeit

LEICHT

Einleitung

Grep ist eines der nützlichsten Werkzeuge, die wir bei der Verwaltung eines Unix-basierten Rechners verwenden können: Seine Aufgabe ist es, nach einem bestimmten Muster in einer oder mehreren Dateien zu suchen und vorhandene Übereinstimmungen zurückzugeben.

In diesem Tutorial werden wir sehen, wie man es benutzt, und wir werden auch seine Varianten untersuchen: egrep und fgrep. Wir werden diesen wirklich berühmten Auszug aus dem Buch "Der Herr der Ringe" in eine Datei packen, und wir werden ihn als Ziel für unsere Beispiele verwenden:

Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all, and in the darkness bind them,
In the Land of Mordor where the Shadows lie.

Die Datei wird lotr.txt genannt.

Grep-Varianten

In der Einleitung haben wir über zwei grep-Varianten gesprochen: egrep und fgrep. Diese Varianten sind eigentlich veraltet, da sie dem Ausführen von grep mit den Optionen -E bzw. -F entsprechen. Bevor wir anfangen zu erklären, worin sich diese Varianten vom Original unterscheiden, müssen wir das Standardverhalten von grep bei der Verwendung regulärer Ausdrücke untersuchen.

Der grundlegende Modus für reguläre Ausdrücke

Ein regulärer Ausdruck ist ein Muster, das nach bestimmten Regeln erstellt wird, um eine Zeichenfolge oder mehrere Zeichenfolgen abzugleichen. Standardmäßig verwendet grep das, was es BRE oder grundlegende reguläre Ausdrücke nennt: In diesem Modus sind nur einige Meta-Zeichen (Zeichen mit einer besonderen Bedeutung innerhalb eines regulären Ausdrucks) verfügbar.

Als erstes Beispiel werden wir versuchen, grep zu verwenden, um eine sehr einfache Zeichenfolge, das Wort "mortal", abzugleichen. Die grep-Syntax ist sehr einfach: Wir rufen das Programm auf, das als erstes Argument das zu passende Muster und als zweites die Zieldatei bereitstellt:

grep mortal lotr.txt

Der obige Befehl gibt keine Übereinstimmungen zurück, obwohl das Wort "mortal" im Text vorkommt: Dies liegt daran, dass grep standardmäßig eine Suche im Modus durchführt, bei der die Groß-/Kleinschreibung beachtet wird, sodass das Wort "Mortal" nicht mit dem von uns bereitgestellten Muster übereinstimmt, da es groß geschrieben wird. Um dieses Problem zu überwinden und eine "allgemeinere" Suche durchzuführen, können wir die Option -i (kurz für --ignore-case, die grep dazu bringt, die Unterscheidung zwischen Groß- und Kleinschreibung zu ignorieren) verwenden:

grep -i mortal lotr.txt

Diesmal erzeugt der Befehl die folgende Ausgabe (die tatsächliche Übereinstimmung ist rot hervorgehoben):

Nine for Mortal Men doomed to die,

Eine wichtige Sache, die Sie beachten sollten, ist, dass grep standardmäßig die gesamte Zeile zurückgibt, in der die Übereinstimmung gefunden wurde. Dieses Verhalten kann jedoch mit der Option -o oder der Langversion --only-matching geändert werden. Wenn Sie diese Option verwenden, wird nur das Spiel selbst gedruckt:

grep -o -i mortal lotr.txt
Mortal

Ein weiterer interessanter Schalter, den wir verwenden können, ist -n, kurz für --line-number. Wenn diese Option verwendet wird, wird die Anzahl der Zeilen, in denen eine Übereinstimmung gefunden wird, in die grep-Ausgabe aufgenommen. Dieser Befehl:

grep -n -i mortal lotr.txt

Erzeugt die folgende Ausgabe:

3:Nine for Mortal Men doomed to die

Dabei ist 3 die Nummer der Zeile, in der die Übereinstimmung gefunden wird.

Was ist, wenn wir nur die tatsächliche Anzahl der gefundenen Übereinstimmungen ermitteln möchten, anstatt die Übereinstimmungen selbst? Grep verfügt über eine dedizierte Option, um dieses Ergebnis zu erhalten: -c oder --count. Wenn Sie den obigen Befehl mit dieser Option verwenden, wird die folgende Ausgabe zurückgegeben:

1

Dies ist, wie erwartet, die Anzahl der Übereinstimmungen, die im Text gefunden wurden.

Grundlegende Meta-Zeichen

Es ist an der Zeit, eine etwas ausführlichere Suche durchzuführen. Wir wollen nun alle Zeilen finden, die mit dem Buchstaben "o" beginnen. Selbst wenn wir mit einfachen regulären Ausdrücken arbeiten, können wir das Zeichen ^ verwenden, um die leere Zeichenkette am Anfang einer Zeile zu finden:

grep -i ^o lotr.txt

Wie erwartet lautet das Ergebnis des Befehls:

One for the Dark Lord on his dark throne
One Ring to rule them all, One Ring to find them,
One Ring to bring them all, and in the darkness bind them,

Das war ziemlich einfach. Nehmen wir nun an, wir möchten unsere Suche weiter einschränken und alle Zeilen finden, die mit einem "o" beginnen und mit einem "," enden. Wir können dieses Beispiel verwenden, um einige andere Meta-Zeichen einzuführen, die wir im grundlegenden Regex-Modus verwenden können:

grep -i ^o.*,$ lotr.txt

Der obige Linux-Befehl gibt genau das zurück, wonach wir gesucht haben:

One Ring to rule them all, One Ring to find them,
One Ring to bring them all, and in the darkness bind them,

Lassen Sie uns erklären, was wir oben getan haben. Zuerst haben wir die Option -i verwendet, um unsere Suche ohne Berücksichtigung der Groß- und Kleinschreibung zu machen, genau wie in den vorherigen Beispielen, dann haben wir das Metazeichen ^ verwendet, gefolgt von einem "o", um nach Zeilen zu suchen, die mit diesem Buchstaben beginnen.

Wir haben dann zwei neue Meta-Zeichen verwendet: . und *. Welche Rolle spielen sie im regulären Ausdruck? Das . entspricht einem einzelnen Zeichen, während das * ein Wiederholungsoperator ist, der null oder mehr Mal auf das vorhergehende Element trifft. Schließlich haben wir das ,, ein Komma, angegeben, das buchstäblich als letztes Zeichen vor dem Ende der Zeile übereinstimmen soll, das sich selbst mit dem Metazeichen $ abgleicht.

Zuordnen eines Zeichensatzes mit eckigen Klammern

Im obigen Beispiel haben wir den Punkt . verwendet, um ein Muster anzugeben, das auf jedes einzelne Zeichen passt. Was wäre, wenn wir nur eine Teilmenge von Zeichen zuordnen wollten? Nehmen wir zum Beispiel an, wir möchten alle Zeilen finden, die mit einem "o" oder einem "i" beginnen: Um ein solches Ergebnis zu erhalten, können wir die Menge der möglichen Zeichen, die übereinstimmen sollen, in eckige Klammern setzen:

grep -i ^[o,i] lotr.txt

Der Befehl führt eine Suche ohne Berücksichtigung der Groß-/Kleinschreibung nach einem "o" oder einem "i" am Anfang einer Zeile durch. Hier ist das Ergebnis:

One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all, and in the darkness bind them,
In the Land of Mordor where the Shadows lie.

Damit das Muster wie oben abgeglichen werden kann, sollte mindestens eines der Zeichen gefunden werden, die in eckigen Klammern enthalten sind. Wenn wir Zeichen in eckigen Klammern angeben, können wir auch einen Bereich angeben, indem wir das Zeichen - verwenden. Um beispielsweise Ziffern abzugleichen, können wir [0-9] schreiben. Zurück zu unserem Text: Wir können diese Syntax verwenden, um Zeilen, die mit den Buchstaben "i" beginnen, mit "s" abzugleichen (Groß- und Kleinschreibung wird nicht beachtet):

grep -i ^[i-s] lotr.txt

Die Ausgabe des Befehls:

Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all, and in the darkness bind them,
In the Land of Mordor where the Shadows lie.

Das Obige ist fast der gesamte Text des Gedichts: Nur die erste Zeile, die mit dem Buchstaben "T" beginnt (nicht in dem von uns angegebenen Bereich enthalten), wurde von der Übereinstimmung ausgeschlossen.

Innerhalb eckiger Klammern können wir auch bestimmte Klassen von Zeichen abgleichen, indem wir vordefinierte Klammerausdrücke verwenden. Einige Beispiele sind:

  • [:alnum:] – alphanumerische Zeichen
  • [:d igit:] – Ziffern von 0 bis 9
  • [:lower:] – Kleinbuchstaben
  • [:upper:] – Großbuchstaben
  • [:blank:] – Leerzeichen und Tabulatoren

Die obige Liste ist nicht vollständig, aber Sie können leicht weitere Beispiele für Klammerausdrücke finden, indem Sie das grep-Handbuch konsultieren.

Umkehren des Ergebnisses einer Übereinstimmung

In den obigen Beispielen haben wir nach jeder Zeile gesucht, die mit einem "o" oder einem "i" beginnt, wobei die Groß- und Kleinschreibung nicht beachtet wurde. Was wäre, wenn wir die entgegengesetzte Ausgabe erhalten und so nur Zeilen ohne Übereinstimmungen finden wollten?

Grep ermöglicht es uns, dieses Ergebnis mit der Option -v (kurz für --invert-match) zu erhalten. Die Option weist grep, wie vorgeschlagen, an, die invertierte Übereinstimmung zurückzugeben. Wenn wir den letzten Befehl ausführen, den wir oben verwendet haben, um diese Option bereitzustellen, sollten wir nur die erste Zeile des Gedichts als Ausgabe erhalten. Lassen Sie es uns überprüfen:

grep -i -v ^[i-s] lotr.txt

Das Ergebnis ist, genau wie wir es erwartet haben, nur die erste Zeile des Gedichts:

Three Rings for the Elven-kings under the sky,

In unserem Beispiel können wir das gleiche Ergebnis erhalten, indem wir der Liste der Zeichen zwischen eckigen Klammern das Zeichen ^ voranstellen, das in diesem Zusammenhang eine andere Bedeutung annimmt, wodurch das Muster nur mit Zeichen übereinstimmt, die nicht in der Liste enthalten sind. Wenn wir ausführen:

grep -i ^[^i-s] lotr.txt

Wir erhalten die gleiche Ausgabe wie zuvor:

Three Rings for the Elven-kings under the sky,

Erweiterter Ausdrucksmodus

Durch die Verwendung von egrep oder grep mit der Option -E (letzteres ist der empfohlene Weg) können wir auf andere Metazeichen zugreifen, die in regulären Ausdrücken verwendet werden sollen. Schauen wir sie uns an.

Fortgeschrittene Wiederholungsoperatoren

Wir haben bereits den Wiederholungsoperator * kennengelernt, der auch im einfachen Modus für reguläre Ausdrücke verfügbar ist. Wenn wir erweiterte Ausdrücke verwenden, haben wir Zugriff auf andere Operatoren dieser Art:

  • ? – stimmt ein- oder nullmal mit dem vorhergehenden Element überein oder
  • + – stimmt mit dem vorhergehenden Element ein oder mehrere Male überein

Wir können auch detailliertere Wiederholungen angeben, indem wir die Syntax für geschweifte Klammern verwenden. Das folgende Muster entspricht z. B. jedem Vorkommen eines doppelten "l":

grep l{2} lort.txt

Die Ausgabe des obigen Befehls lautet:

Seven for the Dwarf-lords in their halls of stone,
One Ring to rule them all, One Ring to find them,
One Ring to bring them all, and in the darkness bind them,

Mit der gleichen Syntax können wir eine minimale Anzahl von Vorkommen angeben, indem wir {x,} verwenden, oder einen gesamten möglichen Bereich, indem wir {x,y} verwenden, wobei x und y jeweils die minimale bzw. die maximale Anzahl von Wiederholungen des vorhergehenden Elements darstellen.

Wechsel

Bei der Arbeit mit erweiterten regulären Ausdrücken haben wir auch Zugriff auf das Meta-Zeichen |, auch inflix-Operator genannt. Indem wir es verwenden, können wir zwei reguläre Ausdrücke verbinden und einen Ausdruck erzeugen, der auf jede Zeichenkette passt, die auf einen der beiden alternativen Ausdrücke passt.

Es ist wichtig zu beachten, dass beide Seiten des inflix-Operators immer versucht werden, abgeglichen zu werden: Das bedeutet, dass dieser Operator nicht als bedingter oder Operator funktioniert, wobei die rechte Seite nur ausgewertet wird, wenn die linke Seite falsch ist: Dies kann überprüft werden, indem die Ausgabe des folgenden Befehls beobachtet wird:

grep -n -E '^O|l{2}' lotr.txt
2:Seven for the Dwarf-lords in their halls of stone,
4:One for the Dark Lord on his dark throne
6:One Ring to rule them all, One Ring to find them,
7:One Ring to bring them all, and in the darkness bind them,

Beachten Sie die Ausgabe: Jede Zeile, die mit einem großen "o" beginnt oder ein doppeltes "l" enthält, wurde in die Ausgabe aufgenommen. In den Zeilen 6 und 7 erzeugten jedoch beide Ausdrücke links und rechts des Operators inflix eine Übereinstimmung. Dies bedeutet, wie oben erwähnt, dass beide Seiten des Operators ausgewertet werden, und wenn beide Seiten eine Übereinstimmung erzeugen, werden beide Übereinstimmungen eingeschlossen.

Fgrep

Wenn grep standardmäßig grundlegende Operatoren für reguläre Ausdrücke unterstützt und wir mit der Option -E oder egrep erweiterte reguläre Ausdrücke verwenden können, können wir mit dem Schalter -F (kurz für –fixed-strings) oder fgrep das Programm anweisen, ein Muster immer als eine Liste von festen Zeichenketten zu interpretieren.

Das bedeutet, dass immer versucht wird, Zeichenketten wörtlich abzugleichen, und alle Meta-Zeichen ihre besondere Bedeutung verlieren. Dies kann nützlich sein, wenn Sie mit einem Text oder einer Zeichenkette arbeiten, die viele Zeichen enthält, die als Operatoren betrachtet werden können, ohne dass sie manuell maskiert werden müssen.

Abschließende Gedanken

In diesem Tutorial haben wir den Befehl grep unix kennengelernt. Wir haben gesehen, wie wir es verwenden können, um Übereinstimmungen in einem Text zu finden, indem wir reguläre Ausdrücke verwenden, und wir haben auch das Verhalten seiner Varianten untersucht: egrep und fgrep. Wir haben einige sehr nützliche Optionen wie -i untersucht, die verwendet werden können, um zwischen Groß- und Kleinschreibung zu unterscheiden.

Schließlich machten wir einen Rundgang durch einige der am häufigsten verwendeten Operatoren für reguläre Ausdrücke. Grep ist definitiv eines der wichtigsten Systemwerkzeuge und verfügt über eine sehr ausführliche Dokumentation: Es ist immer eine gute Idee, es zu konsultieren!

Verwandte Artikel: