Obserwuję następujące zachowanie grep
podczas jego uruchamiania pięć razy:
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$
Nie mogłem zrozumieć, dlaczego dwie ostatnie próby grep
nie zwracają żadnego wyniku .
Odpowiedź
grep
wzorce to wyrażenia regularne (inaczej regex, regexp, RE), podstawowe wyrażenia regularne (BRE), chyba że jedno z -E
/ -F
/ -P
/ -K
/ -X
(tylko pierwsze dwa z nich są standardowe).
*
to operator wyrażenia regularnego, który pasuje do 0 lub więcej poprzedzającego atomu . Na przykład d*
pasuje do 0 lub więcej d
s. W plikach BRE, na początku wzorca lub po
lub \(
operatory regexp, pasuje tylko do literału *
(jest również brane dosłownie wewnątrz [...]
wyrażeń w nawiasach).
Zatem grep "*README.md*"
pasuje do wierszy zawierających literał *
, po którym następuje README
, po którym następuje dowolny pojedynczy znak (operator .
regexp), po którym następuje m
, po którym następuje dowolna liczba d
s. Ponieważ dowolna liczba zawiera 0, to „jest funkcjonalnie równoważne z grep "*README.m"
(co nie miałoby znaczenia dla dopasowywanych wierszy, tylko z tym, co można dopasować w wierszu (co byłoby wyświetlane z opcją --color
na przykład GNU grep
)).
Na przykład , pasuje do tych 2 wierszy:
*README mike ^^^^^^^^^ DONT***README-mddd ^^^^^^^^^^^^
(^
s pokazujące, co w wierszu jest dopasowane za pomocą wyrażenia regularnego, które można było zobaczyć w przypadku --color
)
Tutaj, wygląda na to, że mylisz wyrażenia regularne z wzorcami wieloznacznymi powłoki. Operator wieloznaczny *
, który pasuje do 0 lub więcej znaków, można zapisać .*
w wyrażeniach regularnych. Ale wykonanie:
grep ".*README\.md.*"
znowu wyglądałoby tak samo, jak:
grep "README\.md"
Jak grep
szuka dopasowania wewnątrz linii, zamiast znaleźć wiersze, które dokładnie pasują do wzorca (dla których potrzebujesz -x
).
Z ast-open grep
, czyli również ksh93
„s grep
wbudowany (nie zawsze jest wbudowany domyślnie i musisz go włączyć, umieszczając /opt/ast/bin
przed $PATH
), możesz użyć opcji -K
dla grep
, aby użyć symboli wieloznacznych powłoki (rozszerzone znaki ksh93). Więc z tym grep
, możesz wykonać:
grep -K "README.md"
lub
grep -xK "*README.md*"
do dopasowania w wierszach zawierających README.md
.
W tej samej implementacji dopasowywanie symboli wieloznacznych można również włączyć w rozszerzonym (), rozszerzony (-X
) lub perlopodobny (-P
) zwykły wyrażenia z operatorem (?K)
(i \(?K\)
w podstawowych wyrażeniach regularnych, które faktycznie łamią zgodność z POSIX, więc nie mógłbym na nim polegać można usunąć w przyszłej wersji). Możesz więc zrobić:
grep -xE "(?K)*README.md*"
tam.
Z każdą nowoczesną implementacją grep
, możesz również:
grep -F README.md
W przypadku wyszukiwania ustalonego ciągu (gdzie .
powyżej pasuje do literału .
zamiast dowolnego znaku).
*
lub+
na początku wyrażenia regularnego, podobnie jakgrep -P
grep -E
z kilkoma implementacjami. To*
traktowane dosłownie, gdy na początku jest określone tylko dla BRE. W przypadku innych RE, YMMV.grep
(lubgrep -G
).grep -K
, który używa wzorców powłoki (gdzie*
pasuje do dowolnej liczby znaków).*
nie jest specjalny, gdy pierwszy znak w BRE, zobacz specyfikacja POSIX