Grep Regex enthält keine Zeichenfolge

181

Ich übergebe eine Liste von Regex-Mustern grep, um sie mit einer Syslog-Datei zu vergleichen. Sie stimmen normalerweise mit einer IP-Adresse und einem Protokolleintrag überein.

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

Es ist nur eine Liste von Mustern wie der "1\.2\.3\.4.*Has exploded"Teil, den ich übergebe, in einer Schleife, sodass ich zum Beispiel nicht "-v" übergeben kann.

Ich bin verwirrt, wenn ich versuche, das Gegenteil von oben zu tun. Eine NICHT übereinstimmende Zeile mit einer bestimmten IP-Adresse und einem bestimmten Fehler, sodass "! 1.2.3.4. * Ist explodiert" mit Syslog-Zeilen für alles andere als 1.2.3.4 übereinstimmt und mir mitteilt, dass sie explodiert ist . Ich muss in der Lage sein, eine IP anzugeben, die NICHT übereinstimmt.

Ich habe verschiedene ähnliche Beiträge auf StackOverflor gesehen, aber sie verwenden Regex-Muster, mit denen ich scheinbar nicht arbeiten kann grep. Kann jemand grepbitte ein funktionierendes Beispiel dafür geben ?

UPDATE: Dies geschieht in einem Skript wie diesem.

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
quelle
Meinen Sie damit, dass Sie manchmal einem Muster entsprechen möchten, aber manchmal alles außer einem bestimmten Muster? (Dies scheint eine seltsame Anforderung zu sein, aber was auch immer). Warum iterieren Sie in diesem Fall nicht über zwei verschiedene Musterlisten?
Beerbajay
Nun, ich kenne mich mit Regex nicht sehr gut aus. Ich möchte nicht nach "Has Exploded" suchen, weil ich dies nicht über jedes Protokollierungsgerät wissen möchte. Kann ich also irgendwie in einer Anweisung nach "Has Exploded" und! 9.10.11.12 suchen?
Jwbensley
Wenn Sie es unbedingt in einer Aussage tun müssen, sind negative Lookbehinds der richtige Weg, wie Neil vorschlägt. Siehe meinen Kommentar dort.
Beerbajay
Verwenden Sie die Regex-Übereinstimmung im PCRE-Stil und eine negative Lookahead-Behauptung gemäß der Antwort von @Neil: patterns[3]="\!9\.10\.11\.12.*Has exploded"Änderungen an patterns[3]="(?<!9\.10\.11\.12).*Has exploded"und grep "${patterns[$i]}" logfile.logÄnderungen an grep -P "${patterns[$i]}" logfile.logPCRE setzen standardmäßig mehr Metazeichen voraus, sodass einige der Escapezeichen möglicherweise aus anderen übereinstimmenden Ausdrücken entfernt werden müssen.
Codex24

Antworten:

340

greppasst, grep -vmacht das Gegenteil. Wenn Sie "A, aber nicht B" anpassen müssen, verwenden Sie normalerweise Rohre:

grep "${PATT}" file | grep -v "${NOTPATT}"
beerbajay
quelle
Dies geht in die Mitte einer Schleife, wie ich bereits erwähnt habe, und ich übergebe nur das MUSTER an grep, damit ich "-v" nicht wie erwähnt verwenden kann. Ich gehe nur eine Liste von MUSTERN durch und gehe zu grep.
Jwbensley
1
Sie können es tatsächlich verwenden -vund Sie können es in einer Schleife verwenden. Möglicherweise müssen Sie Ihre Einschränkungen genauer beschreiben, oder Sie haben eine falsche Vorstellung davon, wie Ihr Skript funktionieren soll. Versuchen Sie, einen Code zu veröffentlichen.
Beerbajay
Vielen Dank, beerbajay, ich habe dem ursprünglichen Beitrag einen Code hinzugefügt, um einen Kontext zu geben. Verstehst du was ich jetzt meine?
Jwbensley
Diese Antwort ist nicht ganz richtig, aber Sie haben so ziemlich beerbajay geschrieben, ich musste die Schleife überdenken und am Ende -v verwenden. Danke für den
Hinweis
1
Aber was ist, wenn A aus B besteht? Mit anderen Worten, was ist, wenn ich Linien ohne A und Linien mit AB abgleichen möchte ? Ein Rohr funktioniert nicht.
Pawamoy
15
(?<!1\.2\.3\.4).*Has exploded

Sie müssen dies mit -P ausführen, um ein negatives Aussehen zu erhalten (regulärer Perl-Ausdruck). Der Befehl lautet also:

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

Versuche dies. Es verwendet negatives Lookbehind, um die Zeile zu ignorieren, wenn sie vorangestellt ist 1.2.3.4. Hoffentlich hilft das!

Neil
quelle
1
Ich bin mir ziemlich sicher, dass grepdas Lookaround nicht unterstützt. Es sei denn, Sie verwenden Gnu grepund verwenden den --PParameter, um eine PCRE-Engine zu verwenden.
Tim Pietzcker
Nein, grep unterstützt diese Art von Regex nicht. $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: Syntaxfehler in der Nähe eines unerwarteten Tokens `('
jwbensley
Sie müssen den regulären Ausdruck zitieren, wenn er Zeichen enthält, die von der Shell interpretiert werden.
Beerbajay
korrektes grep -P '(?<!1\.2\.3\.4) Has exploded' test.logAnführungszeichen : Beachten Sie, dass das Lookbehind nur für die Zeichen unmittelbar vor dem übereinstimmenden Teil des Ausdrucks 1.2.3.4 FOO Has explodedfunktioniert. Wenn also zwischen Adresse und Nachricht andere Dinge stehen, z. B. funktioniert dies nicht.
Beerbajay
@ TimPietzcker, sehr aufmerksam. Ich werde das der Frage hinzufügen. Bitte beachten Sie auch, dass es .*nach dem negativen Look ein Verhalten gibt, da sein Beispiel es auch hat. Ich kann mir vorstellen, dass dazwischen ein anderer Text liegt.
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

sollte das gleiche sein wie

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
Krecker
quelle