Ich beobachte das folgende Verhalten von grep
beim Ausführen fünfmal:
me@asus:~/go/src/company/topology-front$ lsof |grep "READ" vim 4788 me 4u REG 8,2 12288 32247694 /home/me/go/src/company/topology-front/.README.md.swp me@asus:~/go/src/company/topology-front$ lsof |grep "README.md*" vim 4788 me 4u REG 8,2 12288 32247694 /home/me/go/src/company/topology-front/.README.md.swp me@asus:~/go/src/company/topology-front$ lsof |grep "README.md" vim 4788 me 4u REG 8,2 12288 32247694 /home/me/go/src/company/topology-front/.README.md.swp me@asus:~/go/src/company/topology-front$ lsof |grep "*README.md*" me@asus:~/go/src/company/topology-front$ lsof |grep "*README.md" me@asus:~/go/src/company/topology-front$
Ich konnte nicht verstehen, warum die letzten beiden Versuche von grep
kein Ergebnis zurückgeben .
Antwort
grep
Muster sind reguläre Ausdrücke (auch bekannt als Regex, Regexp, RE), grundlegende reguläre Ausdrücke (BRE), es sei denn, einer der -E
/ -F
/ -P
/ -K
/ -X
Option (nur die ersten beiden sind Standard) wird verwendet. P. >
*
ist ein Regexp-Operator, der 0 oder mehr des vorhergehenden Atoms entspricht. Beispiel: d*
entspricht 0 oder mehr d
s. In BREs, wenn zu Beginn des Musters oder wenn Sie dem
oder \(
Regexp-Operatoren, es entspricht nur einem Literal *
(es wird auch verwendet) buchstäblich innerhalb von [...]
Klammerausdrücken).
grep "*README.md*"
stimmt also mit Zeilen überein, die ein Literal gefolgt von README
gefolgt von einem einzelnen Zeichen (der Regexp-Operator .
) gefolgt von m
gefolgt von einer beliebigen Anzahl von d
s. Da jede Zahl 0 enthält, entspricht dies funktional grep "*README.m"
(was keinen Unterschied machen würde, welche Zeilen abgeglichen werden, nur auf dem, was abgeglichen werden kann innerhalb der Zeile (die beispielsweise mit der Option --color
von GNU grep
angezeigt wird).
Zum Beispiel würde es in diesen 2 Zeilen übereinstimmen:
*README mike ^^^^^^^^^ DONT***README-mddd ^^^^^^^^^^^^
(die ^
zeigen, was in der Zeile übereinstimmt durch den regulären Ausdruck, den Sie mit --color
)
sehen konnten. Hier scheinen Sie reguläre Ausdrücke mit Shell-Platzhaltermustern zu verwechseln. Der Platzhalteroperator *
, der mit 0 oder mehr Zeichen übereinstimmt, kann in regulären Ausdrücken .*
geschrieben werden. Aber Folgendes zu tun:
grep ".*README\.md.*"
wäre wieder dasselbe wie:
grep "README\.md"
As grep
sucht nach einer Übereinstimmung innerhalb innerhalb der Linie, anstatt Linien zu finden, die genau dem Muster entsprechen (für die Sie -x
).
Mit ast-open grep
, was auch ksh93
„s integriert (standardmäßig nicht immer integriert, und Sie müssen es aktivieren, indem Sie /opt/ast/bin
vor $PATH
) können Sie die Option -K
für grep
verwenden, um Shell-Platzhalter (erweiterte ksh93-Karten) zu verwenden. Mit dieser grep
Implementierung können Sie Folgendes ausführen:
grep -K "README.md"
oder
grep -xK "*README.md*"
für Übereinstimmungen in Zeilen, die README.md
enthalten.
Mit derselben Implementierung kann der Platzhalterabgleich auch für erweiterte (), augmented (-X
) oder perlartig (-P
) regulär Ausdrücke mit dem Operator (?K)
(und \(?K\)
in regulären Grundausdrücken, die die POSIX-Konformität tatsächlich brechen, sodass ich mich nicht darauf verlassen würde könnte in einer zukünftigen Version entfernt werden). Sie können also Folgendes tun:
grep -xE "(?K)*README.md*"
dort.
Mit jeder modernen grep
-Implementierung, Sie können auch Folgendes tun:
grep -F README.md
Für eine Suche mit festen Zeichenfolgen (wobei .
oben mit einem Literal .
anstelle eines beliebigen Zeichens).
Kommentare
- FWIW: Perl beschwert sich über
*
oder+
zu Beginn des regulären Ausdrucks, ebenso wiegrep -P
- @ilkkachu Dies gilt auch für
grep -E
mit mehreren Implementierungen. Das*
, das zu Beginn wörtlich behandelt wird, ist nur für BREs angegeben. Mit anderen REs, YMMV. - @St é phaneChazelas ' hat die Spezifikation für das führende Sternchen nicht gefunden . Ist es irgendwo dokumentiert? Ich ' verwende auch
grep
(odergrep -G
). - @iBug, wenn Sie die Antwort genauer lesen, werden Sie ' bemerken, was (ich denke) Sie ' Bezieht sich auf ast-open ' s
grep -K
, das Shell-Muster verwendet (wobei*
entspricht einer beliebigen Anzahl von Zeichen). - @iBug, wenn Sie meinen, dass
*
nichts Besonderes ist, wenn das erste Zeichen einer BRE angezeigt wird, siehe die POSIX-Spezifikation