Korrekter regulärer Ausdruck funktioniert nicht in grep

12

Ich habe diesen regulären Ausdruck:

(?<=prefix).*$

Dies gibt ein beliebiges Zeichen nach der Zeichenfolge "Präfix" zurück und funktioniert problemlos auf allen Online-Regex-Engines (z . B. https://regex101.com ). Das Problem ist, wenn ich diesen Regex in Bash verwende:

grep '(?<=prefix).*$' <<< prefixSTRING

es passt zu nichts. Warum funktioniert dieser reguläre Ausdruck nicht mit grep?

mark009
quelle
10
Dies unterstreicht wirklich, warum regex101 einen POSIX-Flavor-Selektor benötigt, wie er es für JS, Perl / PHP und Python tut. Ich kann nicht zählen, wie oft ich mir das gewünscht habe.
Jared Smith
Außerdem .*$stimmt das mit einer beliebigen Zeichenfolge bis zum Zeilenende (oder dem Ende der Zeichenfolge) überein, nicht nur mit einem beliebigen Zeichen.
ilkkachu

Antworten:

37

Sie haben anscheinend den richtigen regulären Ausdruck definiert, aber nicht die ausreichenden Flags in der Befehlszeile gesetzt, um ihn grepzu verstehen. Weil standardmäßig grepBRE unterstützt und mit -Eflag ERE. Was Sie haben (Vorausschau), ist nur in der PCRE-Regex-Variante verfügbar, die nur in GNU grepmit ihrem -PFlag unterstützt wird.

Angenommen, Sie müssen nur die übereinstimmende Zeichenfolge extrahieren, nachdem prefixSie ein zusätzliches Flag hinzufügen müssen, um -omitzuteilen, grepdass nur der übereinstimmende Teil als gedruckt wird

grep -oP '(?<=prefix).*$' <<< prefixSTRING

Es gibt auch eine Version grep, die standardmäßig PCRE-Bibliotheken unterstützt - pcregrepin der Sie dies einfach tun können

pcregrep -o '(?<=prefix).*$' <<< prefixSTRING

Detaillierte Erklärungen zu verschiedenen Regex-Varianten finden Sie in dieser wundervollen Antwort von Giles und in den Tools, mit denen sie implementiert werden

Inian
quelle
37

Reguläre Ausdrücke gibt es in vielen verschiedenen Geschmacksrichtungen. Was Sie anzeigen, ist ein Perl-ähnlicher regulärer Ausdruck (PCRE, "Perl Compatible Regular Expression").

grepmacht POSIX reguläre Ausdrücke. Dies sind einfache reguläre Ausdrücke (BRE) und erweiterte reguläre Ausdrücke (ERE, falls grepmit der -EOption verwendet). Weitere Informationen finden Sie im Handbuch re_formatoder in einem regexähnlichen Handbuch, auf das sich Ihr grepHandbuch auf Ihrem System bezieht, oder in den POSIX-Standardtexten, auf die ich gerade verwiesen habe.

Wenn Sie GNU verwenden grep, können Sie Perl-ähnliche reguläre Ausdrücke verwenden, wenn Sie grepdie GNU- grepspezifische -POption verwenden.

Beachten Sie auch , dass die grepRenditen Linien standardmäßig nicht Strings aus Linien. Wiederum können Sie mit GNU grep(und einigen anderen grepImplementierungen) die -oOption verwenden, um nur die Bits zu erhalten, die dem angegebenen Ausdruck aus jeder Zeile entsprechen.

Beachten Sie, dass beide -Pund -okeine Standarderweiterungen der POSIX-Spezifikation von sindgrep .

Wenn Sie GNU nicht verwenden grep, können Sie sedstattdessen Folgendes verwenden , um das Bit zwischen dem String prefixund dem Zeilenende abzurufen:

sed -n 's/.*prefix\(.*\)/\1/p' file

Auf diese Weise werden nur die Zeilen gedruckt, sedauf die die angegebene Ersetzung angewendet werden kann. Die Ersetzung ersetzt die gesamte Zeile, die mit dem Ausdruck (der eine BRE ist) übereinstimmt, durch den Teil davon, der nach der Zeichenfolge auftritt prefix.

Beachten Sie, dass bei mehreren Instanzen von prefixin einer Zeile die sedVariation die Zeichenfolge nach der letztengrep zurückliefern würde , während die GNU- Variation die Zeichenfolge nach der ersten zurückliefern würde (die die anderen Instanzen von enthält prefix).

Die sedLösung wäre portabel auf alle Unix-ähnlichen Systeme.

Kusalananda
quelle
6

Wie in den anderen Antworten angegeben, grepwird bei Lookbehinds keine Regex-Variante verwendet (standardmäßig mit GNU grepoder überhaupt nicht mit anderen Versionen).

Wenn Sie feststellen, dass Sie GNU grepoder nicht verwenden können pcregrep, können Sie es verwenden, perlwenn Sie es haben.

Das Kommandozeilenäquivalent zu perlwäre:

perl -ne 'print if /(?<=prefix).*$/' <<< prefixSTRING

Sie setzen die gewünschte Regex zwischen die Schrägstriche. Wenn Sie Perl verwenden, wird die reguläre Ausdrucksweise von Perl verwendet .

Quantum
quelle
oder print "$&\n" if ...wenn sie nur den Teil nach demprefix
ilkkachu