Negatywne dopasowanie za pomocą grep (dopasuj linie, które nie zawierają foo)

990

Próbowałem wypracować składnię tego polecenia:

grep ! error_log | find /home/foo/public_html/ -mmin -60

LUB:

grep '[^error_log]' | find /home/baumerf/public_html/ -mmin -60

Muszę zobaczyć wszystkie pliki, które zostały zmodyfikowane, z wyjątkiem tych o nazwach error_log.

Przeczytałem o tym tutaj , ale znalazłem tylko jeden notwzór wyrażenia regularnego.

jerrygarciuh
źródło
13
[^ error_log] i tak by nigdy nie działał, [] to klasy char, wyrażenia regularne generalnie nie są dobre w negatywnych wzorcach (chyba że silnik implementuje negatywne lookaheads).
Jaap

Odpowiedzi:

1755

grep -v jest twoim przyjacielem:

grep --help | grep invert  

-v, - odwróć dopasowanie wybierz niepasujące linie

Zobacz także powiązane -L(uzupełnienie -l).

-L, --files-without-match tylko wypisuje nazwy PLIKÓW nie zawierające dopasowania

Motti
źródło
124
Warto wspomnieć, że w przypadku wielu meczów (negatywnych) -emożna użyć opcji:grep -v -e 'negphrase1' -e 'negphrase2'
Babken Vardanyan
31
Podobne do komentarza @ Babken-Vardanyan Również - w stanie używać rur do łączenia wielu meczów np.grep -v 'negphrase1|negphrase2|negphrase3'
Nicholas Adams
13
Ostatni komentarz NIE jest taki sam, ponieważ będzie wyszukiwał rzeczy, które nie pasują do obu, a nie do obu. tzn. jeśli pasuje do jednego, ale nie do drugiego, nadal jest drukowany. Spróbuj tego w obie strony z nie podobnymi ciągami
Evan Langlois,
7
@EvanLanglois - zmuszanie grepa do interpretacji wzorca jako rozszerzonego wyrażenia regularnego przy użyciu -Eutworów, tj. grep -vE 'negphrase1|negphrase2|negphrase3'
Zlemini,
1
@ OlleHärstedt, myślę, że źle zrozumiałem twój scenariusz w poprzednim komentarzu, może być to, czego szukasz grep "" /dev/null * | grep foo | grep -v bar | cut -d: -f1 | sort -u( dlaczego pierwszy grep? Zawsze istnieje sposób :))
Motti
139

Możesz również użyć awkdo tych celów, ponieważ pozwala to na przeprowadzanie bardziej złożonych kontroli w bardziej przejrzysty sposób:

Linie niezawierające foo:

awk '!/foo/'

Linie nie zawierające fooani bar:

awk '!/foo/ && !/bar/'

Linie zawierające ani fooani barktóre zawierają albo foo2albo bar2:

awk '!/foo/ && !/bar/ && (/foo2/ || /bar2/)'

I tak dalej.

fedorqui „SO przestań szkodzić”
źródło
2
To naprawdę całkiem fajne. Nie musisz nawet uczyć się pełnego języka awk, aby grupować wyrażenia regularne z operatorami logicznymi. Dzięki za tę odpowiedź!
Peter T.
1
Właśnie tego szukałem, wielkie dzięki.
mmrs151
13

W twoim przypadku prawdopodobnie nie chcesz używać grep, ale zamiast tego dodaj komendę negatywną do polecenia find, np

find /home/baumerf/public_html/ -mmin -60 -not -name error_log

Jeśli chcesz dołączyć znaki wieloznaczne do nazwy, musisz je uciec, np. Aby wykluczyć pliki z sufiksem .log:

find /home/baumerf/public_html/ -mmin -60 -not -name \*.log
tata Smerf
źródło