it-swarm.com.de

Wie mache ich ein nicht gieriges Match in grep?

Ich möchte die kürzeste Übereinstimmung finden und das Muster sollte ungefähr so ​​aussehen:

<car ... model=BMW ...>
...
...
...
</car>

... bedeutet ein beliebiges Zeichen und die Eingabe ist mehrzeilig.

159
syker

Sie suchen nach einem nicht gierigen (oder faulen) Match. Um eine nicht gierige Übereinstimmung in regulären Ausdrücken zu erhalten, müssen Sie den Modifizierer ? Nach dem Quantifizierer verwenden. Zum Beispiel können Sie .* In .*? Ändern.

Standardmäßig unterstützt grep keine non-greedy-Modifikatoren, Sie können jedoch grep -P Verwenden, um die Perl-Syntax zu verwenden.

249
Mark Byers

Tatsächlich das .*? funktioniert nur in Perl. Ich bin nicht sicher, was die äquivalente grep erweiterte Regexp-Syntax sein würde. Glücklicherweise können Sie Perl-Syntax mit grep verwenden, also grep -P würde funktionieren aber grep -E das ist das gleiche wie egrep würde nicht funktionieren (es wäre gierig).

Siehe auch: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html

80
John Smith

grep

Für eine nicht gierige Übereinstimmung in grep können Sie eine negierte Zeichenklasse verwenden. Versuchen Sie mit anderen Worten, Platzhalter zu vermeiden.

Um beispielsweise alle Links zu JPEG-Dateien aus dem Seiteninhalt abzurufen, verwenden Sie Folgendes:

grep -o '"[^" ]\+.jpg"'

Um mit mehreren Zeilen umzugehen, leiten Sie die Eingabe zuerst durch xargs. Verwenden Sie für die Leistung ripgrep .

10
kenorb

Mein Grep, der nach dem Ausprobieren von Sachen in diesem Thread funktioniert:

echo "hi how are you " | grep -shoP ".*? "

Stellen Sie einfach sicher, dass Sie an jede Ihrer Zeilen ein Leerzeichen anhängen

(Meins war eine zeilenweise Suche, um Wörter auszuspucken)

9
jonz

Die kurze Antwort verwendet den nächsten regulären Ausdruck:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - das ergibt eine Übereinstimmung über mehrere Zeilen hinweg
  • . *? - findet jedes Zeichen mehrmals faul (minimale Übereinstimmung)

Eine (etwas) kompliziertere Antwort lautet:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Auf diese Weise können Sie im folgenden Text car1 und car2 abgleichen

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) steht für eine Erfassungsgruppe
  • \ 1 stimmt in diesem Kontext mit dem gleichen Text überein, der zuletzt durch Erfassen von Gruppe 1 abgeglichen wurde
0
jmc