Uczę się Linuksa i mam wyzwanie, którego sam nie potrafię rozwiązać. Oto on:
grep wiersz z pliku, który zawiera 4 liczby z rzędu, ale nie więcej niż 4.
Nie jestem pewien, jak do tego podejść. Mogę wyszukiwać określone liczby, ale nie ich liczbę w ciągu.
1234a12345
być wyświetlany, czy nie?\b\d{4}\b
Odpowiedzi:
Istnieją dwa sposoby interpretacji tego pytania; Zajmę się obydwoma przypadkami. Możesz chcieć wyświetlić linie:
Na przykład wyświetli się (1)
1234a56789
, ale (2) nie.Jeśli chcesz wyświetlić wszystkie wiersze zawierające ciąg czterech cyfr, który sam nie jest częścią żadnej dłuższej sekwencji cyfr, jednym ze sposobów jest:
Korzysta z wyrażeń regularnych Perla , obsługiwanych przez Ubuntu
grep
( GNU grep )-P
. Nie będzie pasować do tekstu podobnego12345
ani nie będzie pasować do1234
ani tych,2345
które są jego częścią. Ale będzie to dopasować1234
in1234a56789
.W wyrażeniach regularnych Perla:
\d
oznacza dowolną cyfrę (to krótki sposób powiedzieć[0-9]
lub[[:digit:]]
).x{4}
dopasowujex
4 razy. ({
}
składnia nie jest specyficzna dla wyrażeń regularnych Perla; jest również w rozszerzonych wyrażeniach regularnych poprzezgrep -E
.) Tak\d{4}
samo jest z\d\d\d\d
.(?<!\d)
jest twierdzeniem negatywnym o zerowej szerokości. Oznacza to „chyba że poprzedza je\d
”.(?!\d)
jest twierdzeniem o negatywnej perspektywie o zerowej szerokości. Oznacza „chyba, że następuje\d
”.(?<!\d)
i(?!\d)
nie dopasowuj tekstu poza ciągiem czterech cyfr; zamiast tego zapobiegną (gdy zostaną użyte razem), aby nie dopasować do siebie ciągu czterech cyfr, jeśli jest on częścią dłuższej sekwencji cyfr.Samo spojrzenie wstecz lub po prostu nie jest wystarczające, ponieważ czterocyfrowa podsekwencja znajdująca się najbardziej na prawo lub na lewo byłaby nadal dopasowywana.
Jedną z korzyści korzystania z asercji z wyprzedzeniem i z wyprzedzeniem jest to, że wzorzec pasuje tylko do samych czterocyfrowych sekwencji, a nie do otaczającego tekstu. Jest to przydatne podczas korzystania z wyróżniania kolorów (z
--color
opcją).Domyślnie w Ubuntu każdy użytkownik ma
alias grep='grep --color=auto'
w swoim~.bashrc
pliku . Tak więc podświetlanie kolorów jest automatycznie wykonywane po uruchomieniu prostej komendy rozpoczynającej się odgrep
(to jest wtedy, gdy aliasy są rozwinięte), a standardowym wyjściem jest terminal (to właśnie sprawdza). Mecze są zazwyczaj podświetlane w odcieniu czerwieni (zbliżonym do cynobru ), ale pokazałem to pogrubioną kursywą. Oto zrzut ekranu:--color=auto
Możesz nawet
grep
drukować tylko pasujący tekst, a nie całą linię, dzięki-o
:Alternatywny sposób, bez asertywności i asercji
Jeśli jednak:
grep
nie obsługuje-P
lub w inny sposób nie chce używać wyrażenia regularnego Perl, i... możesz to osiągnąć za pomocą rozszerzonego wyrażenia regularnego :
Dopasowuje cztery cyfry i otaczający je znak inny niż cyfra - lub początek lub koniec linii. Konkretnie:
[0-9]
dopasowuje dowolną cyfrę (jak[[:digit:]]
lub\d
w wyrażeniach regularnych Perla) i{4}
oznacza „cztery razy”. Tak[0-9]{4}
dopasowuje sekwencję czterocyfrowy.[^0-9]
znaków nie pasuje w zakresie0
through9
. Jest to równoważne[^[:digit:]]
(lub\D
w wyrażeniach regularnych Perla).^
, gdy nie pojawia się w[
]
nawiasach, dopasowuje początek linii. Podobnie,$
dopasowuje koniec linii.|
oznacza lub nawiasy są do grupowania (jak w algebrze). Tak więc(^|[^0-9])
dopasowuje początek linii lub znak niecyfrowy, a($|[^0-9])
dopasowuje koniec linii lub znak niecyfrowy.Tak więc dopasowania występują tylko w wierszach zawierających czterocyfrową sekwencję (
[0-9]{4}
), która jest jednocześnie:(^|[^0-9])
) i($|[^0-9])
).Jeśli z drugiej strony chcesz wyświetlić wszystkie wiersze zawierające czterocyfrową sekwencję, ale nie zawierają one żadnej sekwencji większej niż cztery cyfry (nawet jednej oddzielnej od innej sekwencji tylko czterech cyfr), to koncepcyjnie twoja celem jest znalezienie linii, które pasują do jednego wzoru, ale nie do drugiego.
Dlatego, nawet jeśli wiesz, jak to zrobić za pomocą jednego wzoru, sugeruję coś takiego za pomocą Matta drugiego sugestię,
grep
ing dla dwóch wzorów oddzielnie.Robiąc to, nie korzystasz z żadnej z zaawansowanych funkcji wyrażeń regularnych Perla, więc możesz nie chcieć ich używać. Ale zgodnie z powyższym stylem, oto skrócenie rozwiązania matowego przy użyciu
\d
(i nawiasów klamrowych) zamiast[0-9]
:Ponieważ używa
[0-9]
, sposób Matta jest bardziej przenośny - będzie działał na systemach, w którychgrep
nie obsługuje wyrażeń regularnych Perla. Jeśli użyjesz[0-9]
(lub[[:digit:]]
) zamiast\d
, ale nadal{
}
będziesz używać , uzyskasz przenośność Matta nieco bardziej zwięźle:Alternatywny sposób, z jednym wzorem
Jeśli naprawdę wolisz takie
grep
poleceniegrep
oddzielonych potokiem , jak wyżej)... możesz użyć:
Te
-x
marki flaggrep
wyświetlać tylko linie gdzie cały dopasowania linii (raczej niż jakikolwiek wiersz zawierający mecz).Użyłem wyrażenia regularnego Perla, ponieważ uważam, że w tym przypadku zwięzłość
\d
i\D
znacznie zwiększam jasność. Ale jeśli potrzebujesz czegoś przenośnego dla systemów, w którychgrep
nie obsługuje-P
, możesz je zastąpić za pomocą[0-9]
i[^0-9]
(lub za pomocą[[:digit:]]
i[^[:digit]]
):Sposób działania tych wyrażeń regularnych jest następujący:
W środku
\d{4}
lub[0-9]{4}
odpowiada jednej sekwencji czterech cyfr. Możemy mieć więcej niż jeden z nich, ale musimy mieć co najmniej jeden.Po lewej stronie,
(\d{0,4}\D)*
lub([0-9]{0,4}[^0-9])*
dopasowuje zero lub więcej (*
) przypadki nie więcej niż czterech cyfr, a następnie non-cyfry. Zero cyfr (tj. Nic) jest jedną z możliwości dla „nie więcej niż czterech cyfr”. Odpowiada to (a) pustemu ciągowi lub (b) dowolnemu ciągowi, który kończy się cyfrą i nie zawiera żadnych sekwencji dłuższych niż cztery cyfry.Ponieważ tekst znajdujący się bezpośrednio po lewej stronie centralnej
\d{4}
(lub[0-9]{4}
) musi być pusty lub kończyć się cyfrą, zapobiega to\d{4}
dopasowaniu czterech cyfr, które mają inną (piątą) cyfrę po lewej stronie.Po prawej stronie
(\D\d{0,4})*
lub([^0-9][0-9]{0,4})*
dopasowuje zero lub więcej (*
) wystąpień niecyfrowych, po których następują nie więcej niż cztery cyfry (które, podobnie jak poprzednio, mogą mieć cztery, trzy, dwie, jedną lub nawet żadną). Odpowiada to (a) pustemu ciągowi lub (b) dowolnemu ciągowi rozpoczynającemu się od cyfr i niezawierającym żadnych sekwencji dłuższych niż cztery cyfry.Ponieważ tekst znajdujący się bezpośrednio po prawej stronie centralnej
\d{4}
(lub[0-9]{4}
) musi być pusty lub zaczynać się cyfrą, zapobiega to\d{4}
dopasowaniu czterech cyfr, które mają inną (piątą) cyfrę tuż po prawej stronie.Zapewnia to, że gdzieś występuje czterocyfrowa sekwencja i że nigdzie nie występuje sekwencja pięciu lub więcej cyfr.
Nie jest źle ani źle to robić w ten sposób. Ale być może najważniejszym powodem do rozważenia tej alternatywy jest wyjaśnienie korzyści z używania (lub podobnego) zamiast, jak sugerowano powyżej i w odpowiedzi Matta .
grep -P '\d{4}' file | grep -Pv '\d{5}'
W ten sposób staje się jasne, że Twoim celem jest wybranie wierszy zawierających jedną rzecz, ale nie inną. Ponadto składnia jest prostsza (dlatego może być szybciej zrozumiana przez wielu czytelników / opiekunów).
źródło
Spowoduje to wyświetlenie 4 liczb z rzędu, ale nie więcej
Uwaga ^ oznacza nie
Jest z tym problem, ale nie jestem pewien, jak to naprawić ... jeśli liczba jest na końcu linii, to nie pojawi się.
Ta brzydsza wersja działałaby jednak w tym przypadku
źródło
a12345b
, ponieważ pasuje2345b
.Jeśli
grep
nie obsługuje wyrażeń regularnych perla (-P
), użyj następującego polecenia powłoki:gdzie
printf '[0-9]%.0s' {1..4}
wyprodukuje 4 razy[0-9]
. Ta metoda jest przydatna, gdy masz długie cyfry i nie chcesz powtarzać wzoru (po prostu zamień na4
swój numer, aby wyszukać).Używanie
-w
spowoduje wyszukanie całych słów. Jeśli jednak interesują Cię ciągi alfanumeryczne, takie jak1234a
, dodaj[^0-9]
na końcu wzorca, npUżywanie
$()
jest w zasadzie zastępstwem poleceń . Sprawdź ten post, aby zobaczyć, jakprintf
powtarza wzór.źródło
Możesz wypróbować poniższe polecenie, zastępując
file
rzeczywistą nazwą pliku w systemie:Możesz także sprawdzić ten samouczek pod kątem innych zastosowań polecenia grep.
źródło