Ich versuche zu verstehen, welche Ausdrücke genau der reguläre Ausdruck (^[0-9]..[a-zA-Z ]+$)
im Befehl erkennt grep
(Linux-Terminal)
Ich weiß das, wenn ich den folgenden Befehl schreiben würde:
grep ^[0-9]..[a-zA-Z] filename.txt
Ich werde jede Zeile erkennen, die Ausdrücke wie enthält. 92afg
Aber ich bin mir nicht sicher, was das +$
bedeutet und welche Art von Ausdrücken ich mit dem Befehl erkennen kann.
grep ^[0-9]..[a-zA-Z]+$ filename.txt
Ich habe versucht, eine neue Textdatei zu öffnen und einfach Ausdrücke einzugeben, von denen ich dachte, dass sie erkannt würden, aber keiner davon stimmte überein. Daher wäre ich für eine Erklärung dankbar.
Antwort1
Lassen Sie uns das Ganze aufschlüsseln. Beachten Sie zunächst, dass dieser RegExp die"Erweiterter regulärer Ausdruck"Syntax (ERE) – das +
ist ein Metazeichen, das in der Syntax „Einfacher regulärer Ausdruck“ nicht funktioniert, die grep
standardmäßig verwendet wird (was bedeutet, dass es mit sich selbst übereinstimmen würde und +
an dieser Position ein Literal erfordern würde). Wenn Sie diesen regulären Ausdruck also mit verwenden möchten grep
, müssen Sie die -E
Option übergeben.
- Dies
^
ist ein Anker, der diese Position des regulären Ausdrucks mit dem Zeilenanfang verbindet. - Dies
[0-9]
ist eine Zeichenliste und entspricht jedem einzelnen (1) Zeichen, das in den Sortierbereich zwischen0
und fällt9
. Was genau das umfasst, hängt von der „Sortierreihenfolge“ ab, die unter anderem durch die Umgebungsvariable bestimmt wirdLC_COLLATE
. - Das
.
entspricht jedem einzelnen Zeichen, also..
bedeutet „zwei“ „beliebige zwei Zeichen“. - Das
[a-zA-Z]
ist wieder eine Zeichenliste und entspricht Zeichen (1) , die zwischena
und liegen,z
sowie zusätzlich denen, die zwischenA
und liegenZ
. Was das wiederum bedeutet, hängt von der Sortierreihenfolge ab! - Das
+
bedeutet „eines oder mehrere der vorherigen“ - Dies
$
ist ein Anker, der diese Position des regulären Ausdrucks mit dem Ende der Zeile verbindet.
Ihr RegExist gedacht, um(1) entsprechen allen Zeilen, die
- mit einer beliebigen Ziffer beginnen
- gefolgt von zwei beliebigen Zeichen
- und bis zum Zeilenende nur Buchstaben (aber mindestens einen) enthalten.
(1) Was es tatsächlich bewirken könnte, erfahren Sie weiter unten
Einige Notizen
In Ihrem Beispiel verwenden Sie den regulären Ausdruck ohne Anführungszeichen. Das bedeutet, dass alle Zeichen von der Shell interpretiert werden können, bevor sie an den
grep
Befehl übergeben werden. Wenn Ihr Muster$
Globbing-Zeichen (*
,?
und[...]
Zeichenlisten!) enthält, versucht die Shell möglicherweise, eine Variablenerweiterung durchzuführen (und dabei Teile Ihres RegEx zu ersetzen) oder Globbing-Muster in möglicherweise mehrere Dateinamen zu erweitern, sodass Sie am Ende mehr Argumente in der Befehlszeile haben, als Sie ursprünglich beabsichtigt haben. Andere Zeichen, die für die Shell speziell sind (>
,#
,;
und dergleichen), können zu noch unerwarteterem Verhalten führen. Sie sollten verwendengrep -E '^[0-9]..[a-zA-Z]+$' filename.txt
stattdessen. Beachten Sie, dass Sie die öffnenden und schließenden Anker loswerden können, indem Sie das
-x
Flag verwenden, um eine Übereinstimmung für die ganze Zeile zu erzwingen:grep -x -E '[0-9]..[a-zA-Z]+' filename.txt
Zeichenlisten mit Bereichen (wie
a-z
) sindgefährlichweil sie Ihnen vielleicht nicht das geben, was Sie denken. Naiv könnte man erwarten, dass sie alle Zeichen abgleichen, die zwischen dem Start- und Endzeichen in der ASCII-Tabelle liegen, aber das gilt nur für dasC
Gebietsschema. In anderen Gebietsschemas (und insbesondere in den normalerweise eingestellten Systemgebietsschemas wieen_US.UTF-8
) ist die Sortierreihenfolge etwa so,aAbB ... zZ
dassa-z
auch die meisten Großbuchstaben übereinstimmen. Außerdem erfolgt die Übereinstimmung tatsächlich nicht auf der Ebene einzelner Zeichen, sondern auf der Ebene von „Sortierelementen“, was bedeutet, dass in einigen Gebietsschemas sogarKombinationen aus mehreren Buchstabenkann übereinstimmen (z. B.dzs
in Ungarisch)! Siehediese Antwort(oder allgemein die meisten Antworten von @Stéphane Chazelas zum Thema Mustervergleich) für weitere Einblicke. Wenn Sie sicherstellen möchten, dass Ihre Bereiche funktionieren, legen Sie die Sortierreihenfolge zumindest für den angegebenen Befehl fest überLC_COLLATE="C" grep -E ' ... ' filename.txt
Antwort2
+
steht für „eine oder mehrere Wiederholungen des vorherigen“, $
ist „Zeilenende“. Beachten Sie den Unterschied gegenüber *
„null oder mehr Wiederholungen“.
Es bedeutet also grundsätzlich: Jede Zeile, die mit einer Ziffer beginnt, gefolgt von zwei beliebigen Zeichen und anschließend einem oder mehreren (ggf. Groß-)Buchstaben¹ bis zum Zeilenende.
(¹ Vorsicht, in manchen Gebietsschemas sind möglicherweise nicht nur die 26 Buchstaben enthalten, die Sie in AZ oder az erwarten würden, z. B. è
oder ŷ
je nach Sprache.)
Für eine gute Anleitung zu Regexes empfehle ich dringendGrymoires wunderschöne Website, das ich auch für zB sed
und wärmstens empfehle awk
.
Warum passt es nicht?
+
ist Teil der erweiterten regulären Ausdrücke (und wird andernfalls als wörtliches +
-Zeichen interpretiert).
Verwenden Sie also für die Verwendung +
als „eine oder mehrere Wiederholungen“ das -E
Flag -in grep
und setzen Sie auch den regulären Ausdruck in Anführungszeichen, um Probleme mit Sonderzeichen der Shell zu vermeiden:
grep -E '^[0-9]..[a-zA-Z]+$' filename.txt