Jak grepować, pomijając niektóre wzorce?

87

Chciałbym znaleźć linie w plikach z wystąpieniem jakiegoś wzorca i brakiem innego wzorca. Na przykład muszę znaleźć wszystkie pliki / linie, w tym loomoprócz tych z rozszerzeniem gloom. Więc mogę znaleźć za loompomocą polecenia:

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Teraz chcę wyszukiwać z loomwyłączeniem gloom. Jednak oba poniższe polecenia nie powiodły się:

grep -v 'gloom' -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
grep -n 'loom' -v 'gloom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Co mam zrobić, żeby osiągnąć swój cel?

EDYCJA 1: Mam na myśli toloomigloomsą sekwencje znaków (niekoniecznie słowa). Tak więc potrzebuję na przykładbloombergw danych wyjściowych polecenia i nie potrzebujęungloomy.

EDYCJA 2: Jest próbka moich oczekiwań. W danych wyjściowych polecenia znajdują się oba poniższe wiersze:

Spojrzałem na ikony, które majaczyły przez zasłonę kadzidła.

Arty jest slooming w ponury dzień.

Oba poniższe wiersze nie są wyświetlane w danych wyjściowych polecenia:

To jest ponure, straszne - wspaniali łajdacy cloodsów.

W południowo-zachodniej części hali heigh pyntit

Warsztat tkacki
źródło
Szukasz plików, które odpowiadają Twoim kryteriom lub liniom, które spełniają Twoje kryteria?
Juto
Szukam plików z liniami pasującymi do moich kryteriów. I chcę zobaczyć listę wszystkich zestawów nazwa pliku + numer pasującej linii + pasująca linia.
Loom
Gdyby wiersz był there is a loom in the gloom- czy chciałbyś wydrukować ten wiersz? Po prostu próbuję zrozumieć, czy szukasz tylko linii, w których krosna występuje inaczej niż jako część mroku, lub jeśli naprawdę chcesz wykluczyć linie zawierające mrok, nawet jeśli krosno pojawia się samo w innym miejscu linii. Pomogłoby wysłanie przykładowych danych wejściowych i oczekiwanych wyników.
Ed Morton,
Więc twoje pytanie jest naprawdę How do I find lines containing the string "loom" where "loom" is not preceded by the letter "g"? Gdybyś zamieścił przykładowe dane wejściowe i pożądane dane wyjściowe, bardzo by to pomogło. Odpowiedź na to pytanie zawarta jest w odpowiedziach poniżej.
Ed Morton,
1
@EdMorton - Tak, masz rację - potrzebuję wszystkich wierszy, gdzie występuje loombez poprzedzenia g. (Przepraszam. Zacząłem komentować wczoraj, ale nigdy nie skończyłem. Przypadkowo ten komentarz został wysłany.)
Loom

Odpowiedzi:

105

A może po prostu łańcuch grepsów?

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
houbysoft
źródło
13
W samą porę. Działa świetnie. -v to opcja do wykluczenia. Dzięki
Ravi Krishna P
2
Z pytania: Tak więc potrzebuję na przykład bloombergw wyjściu polecenia i nie potrzebuję ungloomy. Jeśli pojedyncza linia zawierałaby „… a Bloomberg nie jest ponury co do perspektyw…”, wyeliminowałbyś tę linię, ale jest pożądana (ponieważ jeśli zawiera bloomberg).
Jonathan Leffler
23

Inne rozwiązanie bez łączenia grep:

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Między nawiasami wykluczasz znak gprzed jakimkolwiek wystąpieniem loom, chyba że loomjest to pierwszy znak wiersza.

Bentoy13
źródło
9

Trochę stary, ale no cóż ...

Rozwiązanie, które otrzymało najwięcej głosów, od @houbysoft nie zadziała, ponieważ wykluczy każdą linię z wyrażeniem „mrok”, nawet jeśli zawiera słowo „loom”. Zgodnie z oczekiwaniami OP, musimy uwzględnić linie z „krosnami”, nawet jeśli mają w sobie również „mrok”. Ta linia musi znajdować się na wyjściu „Arty zasługuje na mrok w ponurym dniu”, ale zostanie to wykluczone przez przykutego grepa, takiego jak

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'

Zamiast tego przykład wyrażenia regularnego egrep z Bentoy13 działa lepiej

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

ponieważ będzie zawierał dowolną linię zawierającą słowo „loom”, niezależnie od tego, czy zawiera on słowo „mrok”. Z drugiej strony, jeśli ma tylko mrok, nie będzie go zawierał, a jest to dokładnie zachowanie, którego chce OP.

Sam
źródło
8

Po prostu użyj awk, jest znacznie prostszy niż grep, jeśli chodzi o jasne wyrażanie warunków złożonych.

Jeśli chcesz pominąć wiersze zawierające oba loomi gloom:

awk '/loom/ && !/gloom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

lub jeśli chcesz je wydrukować:

awk '/(^|[^g])loom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

a jeśli w rzeczywistości chcesz po prostu linie, w których loompojawia się samo w sobie:

awk '/\<loom\>/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)
Ed Morton
źródło
3
Pomyśl o tym, jak chcesz pisać polecenia grep, aby uzyskać linie, które zawierają abca defi ghiw dowolnej kolejności. Teraz porównaj to z awk '/abc/ && /def/ && /ghi/'. Zastanów się teraz, w jaki sposób awk '/loom/ && !/gloom/'w odpowiedziach na tej stronie zapisywany jest odpowiednik grep .
Ed Morton
Nie jestem zbyt zaznajomiony z awk, najwyraźniej istnieją książki o tym poleceniu. Na razie nic mi nie jest z grepem, może któregoś dnia powiem to samo co ty. :)
Juto
2
awk jest standardowym narzędziem UNX (tj. dostępnym we WSZYSTKICH instalacjach UNIX) do przetwarzania plików tekstowych. Do tego został wymyślony i jest w tym bardzo dobry. Jeśli używasz systemu UNIX i analizujesz pliki tekstowe, zapoznaj się z awk z książki Effective Awk Programming, Third Edition autorstwa Arnolda Robinsa. Istnieje niewielka zmiana paradygmatu związana ze condition { action }składnią awks, ale wtedy jest to pestka dla każdego, kto ma jakiekolwiek doświadczenie w języku C lub innym języku bazującym na Algolu.
Ed Morton
Bonus: wyjście takie jak grep -Hn --color:awk '/loom/ && !/gloom/ { gsub(/loom/, color("1;31") "&" color(0)); print color(35) FILENAME color(36) ":" color(32) FNR color(36) ":" color(0) $0; }; function color(c) { return "\033[" c "m"; }'
plątanina
6

-v jest flagą „odwrócone dopasowanie”, więc potokowanie jest bardzo dobrym sposobem:

grep "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)| grep -v "gloom"

Oleg Kokorin
źródło
5

/ * Może wyglądasz coś takiego?

grep -vn "gloom" `grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)`

BACKQUOTES są używane jak nawiasy kwadratowe dla poleceń, więc w tym przypadku, gdy -lwłączone, kod w BACKQUOTES zwróci nazwy plików, a następnie z opcją -vn, aby zrobić to, co chciałeś: mieć nazwy plików, numery linii, a także rzeczywiste linie.

UPDATE Lub z xargs

grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp) | xargs grep -vn "gloom"

Mam nadzieję, że to pomoże. * /

Proszę zignorować to, co napisałem powyżej, to bzdury.

grep -n "loom" `grep -l "loom" tt4.txt` | grep -v "gloom"

               #this part gets the filenames with "loom"
#this part gets the lines with "loom"
                                          #this part gets the linenumber,
                                          #filename and actual line
Juto
źródło
4

Możesz użyć grep -P(perl regex) obsługiwanego negative lookbehind:

grep -P '(?<!g)loom\b' ~/projects/**/trunk/src/**/*.@(h|cpp)

Dodałem \bdla granic słów.

anubhava
źródło
2
Nie musisz patrzeć za siebie, \([^g]\|^\)działa. I to nie wyklucza wierszy zawierających oba loomi gloom.
Kevin
@Kevin: OP chce znaleźć linie za pomocą krosna, ale not gloom.
anubhava
Dokładnie. Jeśli linia ma oba, nie chce tego, ale i tak będzie pasować.
Kevin
@Kevin: To NIE będzie pasować do mroku, ale będzie pasować do krosna (tak jak chce OP).
anubhava
Z pytania: Tak więc potrzebuję na przykład bloombergw wyjściu polecenia i nie potrzebuję ungloomy. Zatem granice słów przynoszą efekt przeciwny do zamierzonego.
Jonathan Leffler
3
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
Jiminion
źródło
Z pytania: Tak więc potrzebuję na przykład bloombergw wyjściu polecenia i nie potrzebuję ungloomy. Jeśli pojedyncza linia zawierałaby „… a Bloomberg nie jest ponury co do perspektyw…”, wyeliminowałbyś tę linię, ale jest pożądana (ponieważ jeśli zawiera bloomberg).
Jonathan Leffler
@JonathanLeffler "Potrzebuję znaleźć wszystkie pliki / linie, w tym krosna, z wyjątkiem tych z przygnębieniem."
Jiminion
3

Po prostu użyj! grep -vwiele razy.

Treść pliku

[root@server]# cat file
1
2
3
4
5

Wyklucz linię lub dopasuj

[root@server]# cat file |grep -v 3
1
2
4
5

Wyklucz linię lub dopasuj wiele

[root@server]# cat file |grep -v 3 |grep -v 5
1
2
4
Tiborcz Kiss
źródło
0

Pytanie: wyszukaj „loom” z wyłączeniem „mrok”.
Odpowiedź:

grep -w 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
Abhinandan
źródło
1
Z pytania: Tak więc potrzebuję na przykład bloombergw wyjściu polecenia i nie potrzebuję ungloomy. Nie sądzę, żeby -wto było rozwiązanie tej zagadki.
Jonathan Leffler