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
jwbensley
źródło
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}"
beerbajay
źródło
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!

Neil
źródło
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"    
krecker
źródło