Probleme mit "+" in grep

7

Ich versuche, einen grep-Befehl zu schreiben, um Zeilen wie die folgenden in einer großen Textdatei zu finden:

<div class="node_thumbnail" data-type="file" name="GOPR0036.MP4_frame000001.jpg" data="813334c25191468c9f1c57afc99fde60" aid="133948" rel="/Files/ToolTipView?fileId=813334c25191468c9f1c57afc99fde60&pageNo=1&NoCache=101016083044" rev="topMiddle">

Das +Symbol scheint jedoch Probleme mit den folgenden Befehlen zu verursachen:

 grep 'data=[a-z,0-9,\"]' file

Viele Treffer

 grep 'data=[a-z,0-9,\"]+' file

Keine Treffer

Martin KS
quelle
1
Eine große HTML-Datei, um genau zu sein ... nicht, dass daran etwas falsch ist ...
Reinier Post
Vergessen Sie nur nicht, die Gewohnheit zu haben: LC_ALL="C" grep ...statt grep ..., so dass [az] immer ASCII-Buchstaben a bis z (dh alle ASCII-Kleinbuchstaben) anstelle von lustigen Alternativen bedeutet (z. B. alle Buchstaben außer "Z", in einige Orte ...)
Olivier Dulac
und [a-z,0-9,\"]enthält 2 Vorkommen von ",", was nicht notwendig ist. Sie können den gleichen Effekt mit[a-z,0-9\"]
Olivier Dulac

Antworten:

14

Wenn Sie +"eines oder mehrere der vorhergehenden Atome" bedeuten möchten , müssen Sie eines der folgenden Aktionen ausführen:

  1. Verwendung -E(Extended Regular Expressions) (oder -PPCRE):

    grep -E 'data=[a-z,0-9,\"]+' file
    
  2. Escape, +damit dies speziell in den Standardausdrücken behandelt wird, die standardmäßig verwendet werden in grep:

    grep 'data=[a-z,0-9,"]\+' file
    
muru
quelle
@MartinKS übrigens, wenn alles, was Sie wollen, die angegebene Anführungszeichenfolge ist data=, können Sie einfach ausführen grep -P 'data=".+?"oder, um nur die Zeichenfolge und sonst nichts zu erhalten : grep -oP '\bdata="\K[^"]+'.
Terdon
2
@MartinKS whoops, um nur die Zeichenfolge zu erhalten, benötigen Sie auch die -oOption. Ich habe meinen vorherigen Kommentar bearbeitet. Und du bist willkommen :)
Terdon
@terdon oder einfach nur sed -n 's/.*data="\([^"][^"]*\)".*/\1/p' file, was vollständig POSIX-kompatibel ist . (Und sed -nE 's/.*data="([^"]+)".*/\1/p' filewird POSIX-konform für die nächste Ausgabe von POSIX sein.)
Wildcard
9

Punkte:

  • +ist ein ERE-Token (Extended Regular Expression), das angibt, dass eines oder mehrere der vorhergehenden Token verwendet werden können, wenn die -EOption von grepverwendet wird oder mit (\+Escapezeichen verwendet wird, wenn BRE (Basic Regex), dh nur regulärgrep

  • Die Zeichenklasse [a-z,0-9,\"]würde keines der Zeichen übereinstimmen zwischen [a-z], [0-9], ,oder ". Dies ist möglicherweise nicht das, was Sie wollen

  • Normalerweise wird die grepgesamte Zeile ausgegeben. Wenn Sie nur den übereinstimmenden Teil ausgeben möchten, verwenden Sie die -oOption vongrep


Anhand Ihres Beispiels können Sie Folgendes tun:

grep -E '\bdata=[a-z0-9"]+\b' file
  • -E aktiviert ERE
  • \b Entspricht den String-Kanten und der Breite Null
  • data=passt data=buchstäblich
  • [a-z0-9"]jedes Zeichen von [a-z], [0-9], und ". +stimmt ein- oder mehrmals mit dem vorherigen Token überein

Ihr aktuelles Muster selbst machen Sie es zu korrigieren, ohne \bdiese Fehlalarme passen würde wie foo fdata=2322ab, data=12ABund so weiter.

Beispiel:

% grep -oE '\bdata=[a-z0-9"]+\b' <<<'<div class="node_thumbnail" data-type="file" name="GOPR0036.MP4_frame000001.jpg" data="813334c25191468c9f1c57afc99fde60" aid="133948" rel="/Files/ToolTipView?fileId=813334c25191468c9f1c57afc99fde60&pageNo=1&NoCache=101016083044" rev="topMiddle"'
data="813334c25191468c9f1c57afc99fde60
heemayl
quelle
-1

Eine andere Option ist die Verwendung von egrep:

egrep 'data=[a-z,0-9,\"]+' file

egrep wird mit grep gebündelt, es ist nur ein Wrapper für grep:

#!/bin/sh
exec grep -E "$@"

Dies ist gut für den interaktiven Gebrauch. Allerdings würde ich in Skripten verwenden grep -E.

Steven Penny
quelle
Bitte nicht empfehlen egrep. Es ist seit vielen Jahren zugunsten von veraltetgrep -E . Wie in den POSIX-Spezifikationen angegeben, wird es weiterhin unterstützt und wird dies wahrscheinlich noch eine Weile sein, aber das aktuelle POSIX (und GNU) grepwurde entwickelt, um das ältere egrepund die fgrepVarianten zu ersetzen, sodass es besser zu verwenden ist grep -Eund grep -fstattdessen.
Terdon
egrep ist gut für den interaktiven Gebrauch
Steven Penny