Grep regex NIE zawiera łańcucha


181

Przekazuję listę wzorców wyrażeń regularnych grepdo sprawdzenia w pliku syslog. Zazwyczaj odpowiadają one adresowi IP i wpisowi do dziennika;

grep "1\.2\.3\.4.*Has exploded" syslog.log

To tylko lista wzorców, takich jak "1\.2\.3\.4.*Has exploded"część, którą mijam, w pętli, więc nie mogę na przykład przekazać „-v”.

Jestem zdezorientowany, próbując wykonać odwrotność powyższego, NIE dopasuj wierszy z pewnym adresem IP i błędem, więc „! 1.2.3.4. * Eksplodował” dopasuje wiersze syslog dla czegoś innego niż 1.2.3.4, mówiąc mi, że wybuchł . I musi być w stanie jak IP, aby nie odpowiadać.

Widziałem różne podobne posty na StackOverflor, jednak używają wzorców wyrażeń regularnych, z którymi wydaje mi się, że nie mogę z nimi pracować grep. Czy ktoś może podać działający przykład grep?

AKTUALIZACJA: Dzieje się tak w takim skrypcie;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done

Czy masz na myśli, że czasami chcesz dopasować wzór, ale innym razem chcesz dopasować wszystko oprócz określonego wzoru? (wydaje się to dziwnym wymogiem, ale cokolwiek). W takim razie dlaczego nie powtórzysz dwóch różnych list wzorców?
— beerbajay

Cóż, nie mam zbyt dużej wiedzy na temat wyrażeń regularnych; Nie chcę grepować za „Has Exploded”, ponieważ nie chcę tego wiedzieć o każdym urządzeniu rejestrującym, więc czy mogę w jakiś sposób grepować za „Has Exploded” i! 9.10.11.12 w jednej instrukcji?
— jwbensley

Jeśli bezwzględnie musisz to zrobić w jednym stwierdzeniu, jak sugeruje Neil, najlepiej jest podejść negatywnie. Zobacz mój komentarz tam.
— beerbajay

Użyj dopasowania wyrażenia regularnego w stylu PCRE i negatywnego potwierdzenia z wyprzedzeniem, zgodnie z odpowiedzią @Neil: patterns[3]="\!9\.10\.11\.12.*Has exploded"zmiany patterns[3]="(?<!9\.10\.11\.12).*Has exploded"i grep "${patterns[$i]}" logfile.logzmiany w grep -P "${patterns[$i]}" logfile.logPCRE domyślnie zakładają więcej metaznaków, więc niektóre znaki specjalne mogą wymagać usunięcia z innych pasujących wyrażeń.
— Codex24

Odpowiedzi:


341

grepdopasowuje, grep -vrobi odwrotność. Jeśli potrzebujesz „dopasować A, ale nie B”, zwykle używasz rur:

grep "${PATT}" file | grep -v "${NOTPATT}"

Przechodzi to w sam środek pętli, jak wspomniałem, i właśnie przekazuję WZÓR do grep, więc nie mogę używać „-v”, jak wspomniałem. Po prostu przeglądam listę WZORÓW i przechodzę do grep.
— jwbensley

1
Możesz naprawdę używać -vi możesz używać go w pętli. Być może musisz sprecyzować swoje ograniczenia, a może masz nieporozumienie co do sposobu działania skryptu. Spróbuj opublikować kod.
— beerbajay

Dzięki beerbajay, dodałem kod wycięty do oryginalnego postu, aby dać trochę kontekstu. Czy rozumiesz, co mam teraz na myśli?
— jwbensley

Ta odpowiedź nie jest do końca poprawna, ale pisałeś już wcześniej, musiałem przemyśleć pętlę i na końcu użyć -v. Dzięki za wskaźnik;)
— jwbensley

1
Ale co, jeśli A składa się z B? Innymi słowy, co jeśli chcę dopasować linie bez A i linie z AB? Rura nie będzie działać.
— pawamoy

15
(?<!1\.2\.3\.4).*Has exploded

Musisz uruchomić to z opcją -P, aby mieć ujemny lookbehind (wyrażenie regularne Perl), więc polecenie to:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Spróbuj tego. Używa ujemnego wyglądu, aby zignorować linię, jeśli poprzedza ją 1.2.3.4. Mam nadzieję, że to pomaga!


1
Jestem pewien, że grepto nie obsługuje lookaround. Chyba że używasz Gnu grepi nie używasz --Pparametru, aby użyć silnika PCRE.
— Tim Pietzcker

Nie, grep nie obsługuje tego typu Regex; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: błąd składni w pobliżu nieoczekiwanego tokena `('
— jwbensley

Będziesz musiał zacytować wyrażenie regularne, jeśli zawiera on znaki interpretowane przez powłokę.
— beerbajay

poprawne cytowanie: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logZauważ, że lookbehind działa tylko na znaki bezpośrednio poprzedzające pasującą część wyrażenia, więc jeśli między adresem a wiadomością są inne rzeczy, np. 1.2.3.4 FOO Has explodedto nie zadziała.
— beerbajay

@TimPietzcker, bardzo spostrzegawczy. Dodam to do pytania. Należy również pamiętać, że .*po negatywnym spojrzeniu jest po nim, ponieważ jego przykład również go ma, wyobrażam sobie, że może być inny tekst pomiędzy.
— Neil

2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

powinien być taki sam jak

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.