Wenn ich ein Dokument greife, das Folgendes enthält:
ThisExampleString
... für den Ausdruck This*String
oder *String
wird nichts zurückgegeben. Allerdings This*
gibt die obigen Zeilen wie erwartet.
Ob der Ausdruck in Anführungszeichen steht, spielt keine Rolle.
Ich dachte, das Sternchen zeigt eine beliebige Anzahl unbekannter Zeichen an? Warum funktioniert es nur, wenn es am Anfang des Ausdrucks steht? Was verwende ich anstelle der Ausdrücke This*String
und, wenn dies beabsichtigtes Verhalten ist *String
?
command-line
bash
grep
regex
Trae
quelle
quelle
* != any number of unknown characters
Lesen Sie das Dokument.)Antworten:
Ein Sternchen in regulären Ausdrücken bedeutet "mindestens 0 Mal mit dem vorhergehenden Element übereinstimmen".
In Ihrem speziellen Fall mit
grep 'This*String' file.txt
versuchen Sie zu sagen: "Hey, grep, passen Sie mir das Wort anThi
, gefolgt vons
null oder mehr Kleinbuchstaben , gefolgt von dem WortString
". Der Kleinbuchstabes
ist nirgends zu findenExample
, daher ignoriert grep ihnThisExampleString
.Im Fall von
grep '*String' file.txt
sagen Sie "grep, passen Sie mir die leere Zeichenfolge - buchstäblich nichts - vor dem WortString
". Natürlich soll das nichtThisExampleString
so gelesen werden. (Es gibt andere mögliche Bedeutungen - Sie können dies mit und ohne-E
Flagge versuchen - aber keine der Bedeutungen entspricht in etwa dem, was Sie hier wirklich wollen.)Da
.
wir wissen, dass dies "jedes einzelne Zeichen" bedeutet, können wir Folgendes tun :grep 'This.*String' file.txt
. Jetzt liest der Befehl grep es richtig:This
gefolgt von einem beliebigen Zeichen (stellen Sie es sich als Auswahl von ASCII-Zeichen vor), das beliebig oft wiederholt wird, gefolgt vonString
.quelle
*
handelt es sich um ein Sonderzeichen, das beispielsweise wie folgt zitiert oder maskiert werden sollte:grep 'This*String' file.txt
oder dies:grep This\*String file.txt
um nicht von unerwarteten Ergebnissen überrascht zu werden.*
ist ein Platzhalter. In grep*
ist ein Operator für reguläre Ausdrücke. Siehe unix.stackexchange.com/q/57957/70524strace grep .* file.txt |& head -n 1
undstrace grep '.*' file.txt |& head -n 1
. Funktioniert auch tatsächlichgrep
mit jedem Unicode-Zeichen (z. B.echo -ne ⇏ | grep ⇏
Ausgängen⇏
)bash
. Dies bedeutet, dass zuerstbash
die Sonderzeichen interpretiert werden und erst nach allen durchgeführten Erweiterungen die Parameter an den erzeugten Prozess übergeben werden. ----- Zum Beispiel dieses Befehl in heftigen Schlag:grep This.\*String file.txt
wird Laichen/bin/grep
mit diesen Parametern 0:grep
, 1:This.*String
2:file.txt
. Beachten Sie, dass Bash den Backslash entfernt hat und das ursprünglich entkommene*
Wort buchstäblich übergeben wurde.grep This.*String file.txt
normalerweise funktionieren, da höchstwahrscheinlich keine Datei vorhanden ist, die dem Shell-Platzhalterausdruck entsprichtThis.*String
. In einem solchen Fall übergibt Bash das Argument standardmäßig wörtlich einschließlich*
.Das
*
Metazeichen in BRE 1 s, ERE 1 s und PCRE 1 s entspricht 0 oder mehr Vorkommen des zuvor gruppierten Musters (wenn ein gruppiertes Muster vor dem*
Metazeichen steht), 0 oder mehr Vorkommen der vorherigen Zeichenklasse (wenn eine Zeichenklasse vorhanden ist) vor dem*
Metazeichen) oder 0 oder mehr Vorkommen des vorherigen Zeichens (wenn weder ein gruppiertes Muster noch eine Zeichenklasse vor dem*
Metazeichen steht);Dies bedeutet, dass im
This*String
Muster als*
Metazeichen, dem weder ein gruppiertes Muster noch eine Zeichenklasse vorangestellt ist, das*
Metazeichen mit 0 oder mehr Vorkommen des vorherigen Zeichens (in diesem Fall dess
Zeichens) übereinstimmt :Um 0 oder mehr Vorkommen eines Zeichens zuzuordnen, möchten Sie 0 oder mehr Vorkommen des
.
Metazeichens zuordnen, das einem beliebigen Zeichen entspricht:Das
*
Metazeichen in BREs und EREs ist immer "gierig", dh es stimmt mit der längsten Übereinstimmung überein:Dies ist möglicherweise nicht das gewünschte Verhalten. Falls dies nicht der Fall ist, können Sie die
grep
PCRE-Engine (mithilfe der-P
Option) einschalten und das?
Metazeichen anhängen , das, wenn es nach dem*
und den+
Metazeichen gesetzt wird, die Gier ändert:1: Grundlegende reguläre Ausdrücke, erweiterte reguläre Ausdrücke und Perl-kompatible reguläre Ausdrücke
quelle
Eine der hier gefundenen Erklärungen Link :
quelle
*
hat eine besondere Bedeutung sowohl als Shell- Globbing- Zeichen ("Wildcard") als auch als Metazeichen für reguläre Ausdrücke . Sie müssen beides berücksichtigen. Wenn Sie jedoch Ihren regulären Ausdruck zitieren, können Sie verhindern, dass die Shell ihn speziell behandelt, und sicherstellen, dass er ihn unverändert weitergibtgrep
. Obwohl Art ähnlich konzeptionell, welche*
Mittel zur Schale ist ganz anders aus , was es bedeutet , zugrep
.Zuerst wird die Shell
*
als Platzhalter behandelt .Du sagtest:
Dies hängt davon ab, welche Dateien in dem Verzeichnis vorhanden sind, in dem Sie sich gerade befinden, wenn Sie den Befehl ausführen. Bei Mustern, die das Verzeichnistrennzeichen enthalten
/
, kann es davon abhängen, welche Dateien auf Ihrem gesamten System vorhanden sind. Sie sollten immer zitieren reguläre Ausdrücke fürgrep
--und einfache Anführungszeichen in der Regel Besten-- sind , es sei denn Sie sicher sind , bist du in Ordnung mit den neun Arten von potentiell überraschend Transformationen führt die Shell sonst vor dem Ausführen -grep
Befehl.Wenn die Shell auf ein
*
Zeichen stößt , das nicht in Anführungszeichen steht , bedeutet dies "null oder mehr Zeichen" und ersetzt das Wort, das es enthält, durch eine Liste von Dateinamen, die dem Muster entsprechen. (Dateinamen , die mit beginnen ,.
sind ausgeschlossen - es sei denn , Ihr Muster selbst beginnt mit.
oder . Sie haben konfiguriert Shell , sie trotzdem schließen) Dies ist bekannt als Globbing --und auch durch den Namen Dateinamen Expansion und Pfadname Expansion .Der Effekt mit
grep
wird normalerweise sein, dass der erste übereinstimmende Dateiname als regulärer Ausdruck verwendet wird - auch wenn es für einen menschlichen Leser ziemlich offensichtlich ist, dass er nicht als regulärer Ausdruck gemeint ist -, während alle anderen Dateinamen automatisch von Ihrem aufgelistet werden glob werden als Dateien verwendet, in denen nach Übereinstimmungen gesucht werden soll. (Sie sehen die Liste nicht - sie wird undurchsichtig weitergegebengrep
.) Sie möchten praktisch nie, dass dies geschieht.Der Grund, warum dies manchmal kein Problem ist - und in Ihrem speziellen Fall zumindest bisher nicht - ist, dass
*
dies in Ruhe gelassen wird, wenn alle der folgenden Aussagen zutreffen :Es gab keine Dateien, deren Namen übereinstimmten. ... oder Sie haben das Globbing in Ihrer Shell deaktiviert, normalerweise mit
set -f
oder gleichwertigset -o noglob
. Aber das ist ungewöhnlich und Sie würden wahrscheinlich wissen, dass Sie es getan haben.Sie verwenden eine Shell, deren Standardverhalten darin besteht, sie in
*
Ruhe zu lassen , wenn keine übereinstimmenden Dateinamen vorhanden sind. Dies ist in Bash der Fall, das Sie wahrscheinlich verwenden, jedoch nicht in allen Bourne-Shells. (Das Standardverhalten in der beliebten Shell Zsh besteht beispielsweise darin, dass Globs entweder (a) erweitern oder (b) einen Fehler erzeugen.) ... oder Sie haben dieses Verhalten Ihrer Shell geändert - wie dies gemacht wird, ist unterschiedlich über Muscheln.Sie haben Ihrer Shell nicht anderweitig mitgeteilt, dass Globs durch nichts ersetzt werden sollen, wenn keine übereinstimmenden Dateien vorhanden sind, und dass in dieser Situation keine Fehlermeldung angezeigt wird . In Bash wäre dies durch Aktivieren der Option
nullglob
oderfailglob
Shell geschehen .Sie können sich manchmal auf # 2 und # 3 verlassen, aber Sie können sich selten auf # 1 verlassen. Ein
grep
Befehl mit einem nicht zitierten Muster, der jetzt funktioniert, funktioniert möglicherweise nicht mehr, wenn Sie andere Dateien haben oder wenn Sie ihn von einem anderen Ort aus ausführen. Zitieren Sie Ihren regulären Ausdruck und das Problem verschwindet.Dann wird der
grep
Befehl*
als Quantifizierer behandelt .Die anderen Antworten - wie die von Sergiy Kolodyazhnyy und von kos - sprechen diesen Aspekt dieser Frage ebenfalls auf etwas andere Weise an. Deshalb ermutige ich diejenigen, die sie noch nicht gelesen haben, dies entweder vor oder nach dem Lesen des Restes dieser Antwort zu tun.
Unter der Annahme,
*
dass es zu grep kommt - was das Zitieren sicherstellen sollte - bedeutetgrep
dies, dass das Element, das davor steht, beliebig oft vorkommen kann , anstatt genau einmal auftreten zu müssen . Es könnte immer noch einmal auftreten. Oder es könnte überhaupt nicht vorhanden sein. Oder es könnte wiederholt werden. Text, der zu einer dieser Möglichkeiten passt, wird abgeglichen.Was meine ich mit "Artikel"?
Ein einzelnes Zeichen . Da
b
Findet ein Zeichenb
,b*
entspricht null oder mehrb
s, alsoab*c
passtac
,abc
,abbc
,abbbc
etc.Da in ähnlicher Weise
.
jedes Zeichen ,.*
entspricht null oder mehr Zeichen 1 , soa.*c
Streichhölzerac
,akc
,ahjglhdfjkdlgjdfkshlgc
, selbstacccccchjckhcc
, usw. OderEine Charakterklasse . Da
[xy]
Streichhölzerx
odery
,[xy]*
entspricht null oder mehr Zeichen , wo jeder entweder istx
odery
damitp[xy]*q
übereinstimmtpq
,pxq
,pyq
,pxxq
,pxyq
,pyxq
,pyyq
,pxxxq
,pxxyq
, usw.Dies gilt auch für Formen Kurzschrift von Zeichenklassen wie
\w
,\W
,\s
, und\S
. Da\w
mit jedem Wortzeichen\w*
übereinstimmt , entspricht es null oder mehr Wortzeichen. OderEine Gruppe . Da
\(bar\)
Streichhölzerbar
,\(bar\)*
Streichhölzer null oder mehrbar
s, alsofoo\(bar\)*baz
passtfoobaz
,foobarbaz
,foobarbarbaz
,foobarbarbarbaz
etc.Behandelt Ihren regulären Ausdruck mit den Optionen
-E
oder als ERE bzw. PCRE und nicht als BRE , und dann werden Gruppen von anstelle von umgeben , sodass Sie stattdessen anstelle von und anstelle von verwenden .-P
grep
(
)
\(
\)
(bar)
\(bar\)
foo(bar)baz
foo\(bar\)baz
man grep
bietet am Ende eine einigermaßen leicht zugängliche Erklärung der BRE- und ERE-Syntax sowie eine Auflistung allergrep
am Anfang akzeptierten Befehlszeilenoptionen . Ich empfehle diese Handbuchseite als Ressource sowie die GNU Grep-Dokumentation und diese Tutorial- / Referenzseite (auf die ich oben mit einer Reihe von Seiten verlinkt habe).Zum Testen und Lernen
grep
empfehle ich, es mit einem Muster, aber ohne Dateinamen aufzurufen. Dann nimmt es Eingaben von Ihrem Terminal entgegen. Zeilen eingeben; Die Zeilen, die an Sie zurückgesendet werden, enthalten Text, mit dem Ihr Muster übereinstimmt. Drücken Sie zum Beenden Ctrl+ Dam Anfang einer Zeile, die das Ende der Eingabe signalisiert. (Oder Sie können wie bei den meisten Befehlszeilenprogrammen Ctrl+ drücken C.) Zum Beispiel:Wenn Sie das
--color
Flag verwenden,grep
werden die spezifischen Teile Ihrer Zeilen hervorgehoben, die Ihrem regulären Ausdruck entsprechen. Dies ist sehr nützlich, um herauszufinden, was ein regulärer Ausdruck bewirkt, und um zu finden, wonach Sie suchen, sobald Sie dies tun. Standardmäßig verfügen Ubuntu-Benutzer über einen Bash-Alias, dergrep --color=auto
zur Ausführung führt - was für diesen Zweck ausreichend ist -, wenn Siegrep
über die Befehlszeile ausgeführt werden, sodass Sie wahrscheinlich nicht einmal--color
manuell übergeben müssen.1 Daher bedeutet
.*
in einem regulären Ausdruck, was*
in einem Shell-Glob bedeutet. Der Unterschied besteht jedoch darin, dassgrep
automatisch Zeilen gedruckt werden, die Ihre Übereinstimmung an einer beliebigen Stelle enthalten. Daher ist es normalerweise nicht erforderlich, sie.*
am Anfang oder Ende eines regulären Ausdrucks zu haben.quelle