grep für "Begriff" und schließen Sie "einen anderen Begriff"


28

Ich versuche, eine grep-Suche zu erstellen, die nach einem Begriff sucht, aber Zeilen ausschließt, die einen zweiten Begriff haben. Ich wollte mehrere -e "pattern"Optionen verwenden, aber das hat nicht funktioniert.

Hier ist ein Beispiel für einen Befehl, den ich ausprobiert habe, und die von ihm generierte Fehlermeldung.

grep -i -E "search term" -ev "exclude term"
grep: exclude term: No such file or directory

Mir ist klar, dass das -vfür alle Suchbegriffe / Suchmuster gilt. Da läuft das dann aber nicht search termin den Ergebnissen mit.

grep -i -E "search term" -ve "exclude term"

Gibt es eine andere Option zum Ausschließen, da wir manchmal Zeilen um ein Wort setzen müssen und wenn wir beim nächsten Vorgang ausschließen, '|' , es entfernt nur dieses Wort, entfernt aber nicht den Block für dieses Wort
Anfänger

Antworten:


40

Für und Ausdrücke mit grep benötigen Sie zwei Aufrufe:

grep -Ei "search term" | grep -Eiv "exclude term"

Wenn es sich bei den gesuchten Begriffen nicht um reguläre Ausdrücke handelt, verwenden Sie eine feste Zeichenfolge ( -F), die schneller ist:

grep -F "search term" | grep -Fv "exclude term"

18

Ohne zweimal grep aufzurufen, gibt es nur einen Weg, dies zu erreichen. Es handelt sich um Perl-kompatible reguläre Ausdrücke (PCRE) und einige ziemlich hacky Look-Around-Behauptungen .

Um nach foo mit Ausnahme von Übereinstimmungen zu suchen , die eine Leiste enthalten , können Sie Folgendes verwenden:

grep -P '(?=^((?!bar).)*$)foo'

So funktioniert das:

  • (?!bar)Stimmt mit allem überein, was nicht gesperrt ist, ohne Zeichen aus der Zeichenfolge zu verbrauchen. Dann .verbraucht ein einzelnes Zeichen.

  • ^((?!bar).)*wiederholt das Obige vom Anfang der Zeichenkette ( ^) bis zum Ende ( $). Es schlägt fehl, wenn bares an einem bestimmten Punkt auftritt, da (?!bar)es nicht übereinstimmt.

  • (?=^((?!bar).)*$) Stellt sicher, dass die Zeichenfolge mit dem vorherigen Muster übereinstimmt, ohne dass Zeichen aus der Zeichenfolge verwendet werden.

  • foosucht wie gewohnt nach foo .

Ich habe gefunden, dass dieser Hack im regulären Ausdruck mit einer Zeichenfolge übereinstimmt, die kein Wort enthält. . In der Antwort von Bart Kiers finden Sie eine viel detailliertere Erklärung, wie die negative Vorausschau funktioniert.


Netter Hack. Dieser Trick funktioniert übrigens auch in Java.
Raman

12

Wenn Sie dies in einem Durchgang tun möchten, können Sie awk anstelle von grep verwenden.

Format:

echo "some text" | awk '/pattern to match/ && !/pattern to exclude/'

Beispiele:

  • echo "hello there" | awk '/hello/ && !/there/'

Gibt nichts zurück.

  • echo "hello thre" | awk '/hello/ && !/there/'

Rückgabe: hallo thre

  • echo "hllo there" | awk '/hello/ && !/there/'

Gibt nichts zurück.

Bei mehreren Mustern können Sie sie mithilfe von Klammern gruppieren.

Beispiele:

  • echo "hello thre" | awk '(/hello/ || /hi/) && !/there/'

Rückgabe: hallo thre

  • echo "hi thre" | awk '(/hello/ || /hi/) && !/there/'

Rückgabe: hi thre

  • echo "hello there" | awk '(/hello/ || /hi/) && !/there/'

Gibt nichts zurück.

  • echo "hi there" | awk '(/hello/ || /hi/) && !/there/'

Gibt nichts zurück.


1
Es hat bei mir funktioniert, aber ich habe die Farben verloren = P
Leopoldo Sanczyk

1
Farben aus welcher Ausgabe? Wenn Sie versuchen, Farben mit ls beizubehalten, verwenden Sie beim Parsen der Ausgabe das Argument "--color = always" (andernfalls gehen die Farben beim Parsen des Texts normalerweise immer verloren). Beispiel: ls --color=always | awk '/hello/ && !/goodbye/'
Philip Reese

Danke für die Antwort @Philip! Das habe ich vorher versucht, aber ohne Erfolg. Ich denke, da das Muster den farbigen Text hat, stimmt er später nicht mehr überein, und ich sollte eine Art Farbcode in das Muster aufnehmen. Auf jeden Fall ist Ihre Methode die schnellste, die ich grep -Rin mehreren Codedateien mithilfe der Ubuntu-Befehlszeile gefunden habe.
Leopoldo Sanczyk

1

Aus meinen Experimenten macht es keinen großen Unterschied, ob Sie Ihre Ausschlussbedingungen durch grepoder leiten sed. Sed hat einige andere nützliche Funktionen zum Ersetzen von Text, die ich oft benutze, um die Ausgabe von Protokolldateien besser zu filtern. Also werde ich sed verwenden, da ich eine ganze Reihe von Filtern auf sed kombiniere.

wc /var/log/tomcat/tomcat.2013-01-14.log.1 
  1851725

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/ login OK / d" -e "/ Login abgelaufen / d" | Toilette
24.05user 0.15system 0: 25.27elapsed 95% CPU (0avgtext + 0avgdata 3504maxresident) k
0inputs + 0outputs (0major + 246minor) pagefaults 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/ login OK / d" -e "/ Login abgelaufen / d" | Toilette
23.50user 0.16system 0: 24.48elapsed 96% CPU (0avgtext + 0avgdata 3504maxresident) k
0inputs + 0outputs (0major + 246minor) pagefaults 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "Login OK" -e "Login abgelaufen" | Toilette
23.08user 0.14system 0: 23.55elapsed 98% CPU (0avgtext + 0avgdata 3504maxresident) k
0inputs + 0outputs (0major + 246minor) pagefaults 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "Login OK" -e "Login abgelaufen" | Toilette
23.50user 0.15system 0: 25.27elapsed 93% CPU (0avgtext + 0avgdata 3488maxresident) k
0inputs + 0outputs (0major + 245minor) pagefaults 0swaps
   5614 91168 1186298


3
Vergleichen Sie grep -Fstattdessen die Laufzeit von grep -Eund verwenden Sie sie nicht, -iwenn Sie sie nicht benötigen.
Thor

1
Aber dann geben Sie keine Beispiele mit sed;)
Benjamin R
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.