Potok znajdź w grep -v

18

Próbuję znaleźć wszystkie pliki określonego typu i nie zawierające określonego ciągu. Próbuję o tym poradzić przesyłając polecenie find do grep -v

przykład:

find -type f -name '*.java' | xargs grep -v "something something"

To nie wydaje się działać. Wygląda na to, że zwraca wszystkie pliki znalezione przez polecenie find. To, co próbuję zrobić, to w zasadzie znaleźć wszystkie pliki .java, które pasują do określonej nazwy pliku (np. Kończą się na „Pb” jak w SessionPb.java) i które nie mają w sobie „rozszerzenia coś”.

Podejrzewam, że robię to źle. Jak więc zamiast tego powinno wyglądać polecenie?

Hyangelo
źródło
możesz dodać, co sprawia, że ​​myślisz, że to nie działa. może twoje grep wyrażenie jest zbyt wyraźne? potrzebuje „-i”, aby rozróżnić wielkość liter? Zobacz też moją odpowiedź poniżej ...
lornix,

Odpowiedzi:

21

Nie ma tu potrzeby xargs. Również trzeba użyć grepz -Lopcją (pliki bez match), bo w przeciwnym razie będzie to wyjście zawartość pliku zamiast jego nazwy, jak w przykładzie.

find . -type f -iname "*.java" -exec grep -L "something somethin" {} \+
wysypka
źródło
1
-Ljuż ma negocjacje, ponieważ to znaczy files _without_ match. Dlatego nie potrzebujesz -vtutaj opcji.
pędzi
3
nie z dodatkowym + na końcu.
lynxlynxlynx
2
@ user946850 za każdym razem, gdy piszę, find -exec \+ktoś pisze mi, że o wiele lepiej jest używać xargs. dlaczego nikt nie patrzy na człowieka przed napisaniem komentarza? (:
pędzi
5
@ user946850 -exec ... {} \+nie jest równoważny z xargs. Przeczytaj dokumentację findutils! (Ciężko nad tym pracowałem!)
James Youngman,
2
@ user946850 tak. Jedną z różnic jest to, że (domyślnie) xargsprzetwarza dane wejściowe i oddziela argumenty na spacji. Cytaty są również specjalne (domyślnie) dla xargs. Żadna z tych rzeczy nie jest prawdziwa -exec ... {} +. Stare wersje xargsuważały podkreślenie za wskaźnik EOF, ale już tak nie jest.
James Youngman,
7

Prawie masz to naprawdę ...

find . -type f -iname "*.java" -print0 | xargs -0 grep -v "something something"

Kropka '.' mówi, żeby zacząć od tego miejsca. (twoje implikuje to ... ale nigdy nie zakładaj).

-iname używa wyszukiwania bez rozróżniania wielkości liter, na wszelki wypadek (lub po prostu nie na wielkość liter).
-print0 wysyła nazwy plików do xargs ze znakiem końcowym \ x00, co zapobiega problemom z nazwami plików zawierającymi spacje.

„-0” na xargs mówi, że oczekuje nazw plików kończących się na \ x00 zamiast zwrotów.

i twoje polecenie grep ...

Prawie to mam.


EDYTOWAĆ::

Z twojej aktualizacji:

find . -type f -iname "*pb.java" -print0 | xargs -0 grep -iL "something"

powinno pomóc. (Dodano -L z odpowiedzi @ rush, dobra robota)

Rozumiem, że twój grep potrzebuje albo opcji „-i”, albo by był mniej wyraźny.

Spróbuj wykonać polecenie w częściach ... czy WYJŚCIE nazwy plików wyjściowych wydają się prawidłowe?

find . -type f -iname "*pb.java"

Jeśli tak, oznacza to, że problem prawdopodobnie nie pasuje do wzorca wyszukiwania grep (błąd pisowni? To się zdarza!) Lub po prostu nie ma żadnych dopasowań.

Absolutnie najgorszy przypadek:

grep -riL "something" *

wykona dużo więcej pracy, szukając wszystkiego, ale powinien dać ci pewien efekt.

lornix
źródło
Wypróbowałem twoje modyfikacje i nadal nie otrzymuję oczekiwanego rezultatu. Spróbuję zaktualizować pytanie, aby było bardziej zrozumiałe.
Hyangelo
Jeśli autor pytania chce tylko znaleźć nazwy plików, czy grep nie powinien być „grep -l -v”?
Bruce Ediger,
szuka określonej zawartości w plikach * .java
lornix,
xargs -0 grep -v "something something"powinno być xargs -0 grep -v "something something" /dev/nullinaczej, otrzymasz dziwne wyniki, gdy find nie utworzy pasujących plików.
James Youngman,
{Grin} tak, gdzieś tam logika jest owłosiona. Nie ma to jak wielokrotny test wielokrotnej fałszywej logiki, który spowodowałby ból głowy.
lornix,
4

Komputer jest komputerem: robi to, co mu kazałeś, zamiast tego, co chciałeś.

grep -v "something something"wypisuje wszystkie linie, które nie zawierają something something. Na przykład drukuje dwie linie spośród następujących trzech:

hello world
this is something something
something else

Aby wydrukować pliki, które extends SomethingSomethingnigdzie nie zawierają , użyj -Lopcji:

grep -L -E 'extends[[:space:]]+SomethingSomething' FILENAME…

Niektóre wersje grep nie mają tej -Lopcji (nie jest to określone przez POSIX ). Jeśli twój nie, niech nic nie wydrukuje i użyj kodu powrotu, aby powłoka wywołująca zrobiła to, co powinna.

grep -q -E 'extends[[:space:]]+SomethingSomething' FILENAME ||
echo "$FILENAME"

Alternatywnie użyj awk.

awk '
    FNR == 1 && NR != 1 && !found { print fn }
    FNR == 1 { fn = FILENAME; found = 0; }
    /extends[[:space:]]+SomethingSomething/ { found = 1 }
    END { if (fn != "" && !found) print fn }
'

W systemie Linux lub Cygwin (lub innym systemie z GNU grep) nie musisz go używać find, ponieważ grepmoże się powtarzać.

grep -R --include='*.java' -L -E 'extends[[:space:]]+SomethingSomething'

Jeśli twoją powłoką jest ksh, bash lub zsh, możesz sprawić, aby powłoka dopasowała nazwę pliku. Uruchom bash jako set -o globstarpierwszy (możesz to umieścić w swoim ~/.bashrc).

grep -L -E 'extends[[:space:]]+SomethingSomething' **/*.java
Gilles „SO- przestań być zły”
źródło
Wow, to jest jeszcze lepsze. Używałem „extends (/ s) + SomethingSomething”, który wydawał się działać, o ile mogłem powiedzieć. Czy jest jakaś różnica w tej składni z tą określoną w rozszerzonej wersji RegEx?
Hyangelo,
@Hyangelo \sto rozszerzenie GNU grep, które moim zdaniem jest synonimem [[:space:]].
Gilles „SO- przestań być zły”