grep dla „term” i wyklucz „inny termin”

26

Próbuję zbudować wyszukiwanie grep, które wyszukuje termin, ale wyklucza wiersze, które mają drugi termin. Chciałem użyć wielu -e "pattern"opcji, ale to nie zadziałało.

Oto przykład polecenia, które próbowałem i komunikat o błędzie, który wygenerowałem.

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

Wydaje mi się, że -vdotyczy wszystkich wyszukiwanych haseł / wzorców. Ponieważ to działa, ale potem nie obejmuje search termwyników.

grep -i -E "search term" -ve "exclude term"
nelaaro
źródło
Czy jest jakaś inna opcja wykluczenia, ponieważ czasami musimy przesuwać linie wokół słowa i Jeśli wykluczymy w następnej operacji za pomocą „|” , po prostu usuwa to słowo, ale nie usuwa bloku dla tego słowa
Uczeń

Odpowiedzi:

39

Do i wyrażenia z grep potrzebujesz dwóch wywołań:

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

Jeśli wyszukiwane terminy nie są wyrażeniami regularnymi, użyj ustalonego dopasowania ciągu ( -F), które jest szybsze:

grep -F "search term" | grep -Fv "exclude term"
Thor
źródło
16

Poza dwukrotnym wywołaniem grep, jest tylko jeden sposób, aby to osiągnąć. Obejmuje wyrażenia regularne zgodne z Perlem (PCRE) i pewne dość hackerskie stwierdzenia .

Aby wyszukać foo z wyłączeniem dopasowań zawierających pasek , możesz użyć:

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

Oto jak to działa:

  • (?!bar)dopasowuje wszystko, co nie zawiera barów bez konsumowania znaków z łańcucha. Następnie .zużywa jedną postać.

  • ^((?!bar).)*powtarza powyższe od początku ciągu ( ^) do końca ( $). Nie powiedzie się, jeśli barzostanie napotkany w danym momencie, ponieważ (?!bar)nie będzie pasował.

  • (?=^((?!bar).)*$) upewnia się, że łańcuch pasuje do poprzedniego wzorca, bez konsumowania znaków z łańcucha.

  • fooszuka foo jak zwykle.

Znalazłem ten hack w wyrażeniu regularnym, aby dopasować ciąg nie zawierający słowa? . W odpowiedzi Barta Kiersa można znaleźć znacznie bardziej szczegółowe wyjaśnienie działania negatywnego przewidywania.

Dennis
źródło
Niezły hack. Ta sztuczka działa również w Javie, btw.
Raman
10

Jeśli chcesz to zrobić za jednym razem, możesz użyć awk zamiast grep.

Format:

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

Przykłady:

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

Nic nie zwraca.

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

Zwraca: cześć

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

Nic nie zwraca.

W przypadku wielu wzorców możesz użyć nawiasów, aby je zgrupować.

Przykłady:

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

Zwraca: cześć

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

Zwraca: cześć

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

Nic nie zwraca.

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

Nic nie zwraca.

Philip Reese
źródło
1
To działało dla mnie, ale straciłem kolory = P
Leopoldo Sanczyk
1
Kolory z jakiej produkcji? Jeśli próbujesz zachować kolory za pomocą ls, używaj argumentu „--color = always” za każdym razem, gdy analizujesz dane wyjściowe (lub zwykle zawsze tracisz kolory podczas analizowania tekstu). Przykład: ls --color=always | awk '/hello/ && !/goodbye/'
Philip Reese,
Dzięki za odpowiedź @Philip! Próbowałem już wcześniej, ale bez powodzenia. Wydaje mi się, że ponieważ wzór ma kolorowy tekst, nie pasuje później i powinienem do niego dołączyć kod koloru. W każdym razie twój jest najszybszym sposobem, jaki znalazłem grep -Rw kilku plikach kodu za pomocą wiersza poleceń Ubuntu.
Leopoldo Sanczyk
1

Z moich eksperymentów nie ma większego znaczenia, jeśli wprowadzisz warunki wykluczenia przez greplub sed. Sed ma kilka innych przydatnych funkcji zastępowania tekstu, których często używam do lepszego filtrowania plików dziennika. Więc użyję sed, ponieważ łączę sporo filtrów na sed.

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 "/ Logowanie wygasło / d" | toaleta
24.05 użytkownik 0,15 system 0: 25,27 upłynął 95% procesora (0avgtext + 0avgdata 3504maxresident) k
0 wejść + 0 wyników (0 głównych + 246 mniejszych) błędów strony 0 zamiany
   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 "/ Logowanie wygasło / d" | toaleta
23,50 użytkownik 0,16 system 0: 24,48 upłynął 96% procesor (0avgtext + 0avgdata 3504maxresident) k
0 wejść + 0 wyników (0 głównych + 246 mniejszych) błędów strony 0 zamiany
   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 „Logowanie wygasło” | toaleta
23.08 użytkownik 0.14 system 0: 23.55 upłynął 98% procesor (0avgtext + 0avgdata 3504maxresident) k
0 wejść + 0 wyników (0 głównych + 246 mniejszych) błędów strony 0 zamiany
   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 „Logowanie wygasło” | toaleta
23,50 użytkownik 0,15 system 0: 25,27 upłynął 93% procesor (0avgtext + 0avgdata 3488maxresident) k
0 wejść + 0 wyjść (0 głównych + 245 mniejszych) błędy stron 0 zamiany
   5614 91168 1186298

nelaaro
źródło
3
Spróbuj porównać środowisko uruchomieniowe grep -Fzamiast grep -Ei nie używaj go, -ijeśli go nie potrzebujesz.
Thor
1
Ale wtedy nie podajesz przykładów przy użyciu sed;)
Benjamin R