Pesquisa de pipe no grep -v

18

Estou tentando encontrar todos os arquivos que são de um determinado tipo e não contêm uma determinada string. Eu estou tentando fazer isso encanando encontrar grep -v

exemplo:

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

Isso não parece funcionar. Parece estar apenas retornando todos os arquivos que o comando find encontrou. O que estou tentando fazer é basicamente encontrar todos os arquivos .java que correspondam a um determinado nome de arquivo (por exemplo, termina com 'Pb' como no SessionPb.java) e que não possuem um 'estende SomethingSomething "dentro dele.

Minha suspeita é que estou fazendo errado. Então, como deve ser o comando?

Hyangelo
fonte
você pode adicionar o que faz você pensar que não funcionou. talvez sua expressão grep seja muito explícita? precisa de um '-i' para insensibilidade de maiúsculas e minúsculas? Veja a minha resposta abaixo também ...
lornix 5/12

Respostas:

20

Não há necessidade xargsaqui. Também é necessário usar grepcom a -Lopção (arquivos sem correspondência), pois, caso contrário, ele exibirá o conteúdo do arquivo em vez de seu nome, como no seu exemplo.

find . -type f -iname "*.java" -exec grep -L "something somethin" {} \+
pressa
fonte
1
-Ljá tem negociação, porque significa files _without_ match. Portanto, você não precisa de -vopção aqui.
apressar
3
não com o extra + no final.
Lynxlynxlynx
2
@ user946850 toda vez que escrevo find -exec \+alguém me escreve que é muito melhor usar xargs. por que ninguém parece homem antes de escrever um comentário? (:
rush
5
@ user946850 -exec ... {} \+não é equivalente a xargs. Por favor, leia a documentação do findutils! (Eu trabalhei muito duro para isso!)
James Youngman
2
@ user946850 sim. Uma das diferenças é que (por padrão) xargsprocessa sua entrada e separa argumentos no espaço em branco. As cotações também são especiais (por padrão) para xargs. Nenhuma dessas coisas é verdadeira -exec ... {} +. As versões antigas xargscostumavam considerar o sublinhado como um indicador EOF, mas esse não é mais o caso.
James Youngman
7

Você quase entendeu mesmo ...

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

O ponto '.' diz para começar a partir daqui. (o seu implica ... mas nunca assuma).

-iname usa pesquisa sem distinção entre maiúsculas e minúsculas, apenas no caso (ou apenas no caso não).
-print0 envia nomes de arquivos para xargs com um caractere \ x00 à direita, o que evita problemas com nomes de arquivos com espaços neles.

o '-0' no xargs diz esperar nomes de arquivos que terminem com \ x00 em vez de retornos.

e seu comando grep ...

Praticamente entendi.


EDITAR::

Na sua atualização:

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

deve ajudar. (Adicionado -L da resposta do @ rush, bom trabalho)

Tenho a ideia de que seu grep precisa da opção '-i' ou para ser menos explícito.

Tente o comando em partes ... ESTE nome de arquivo de saída parece adequado?

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

Nesse caso, é provável que o seu problema seja o padrão de pesquisa grep (erro de ortografia? Acontece!) Ou simplesmente não há correspondências.

Pior caso absoluto:

grep -riL "something" *

fará muito mais trabalho pesquisando tudo, mas deverá fornecer alguma saída.

lornix
fonte
Eu tentei suas modificações e ainda não estou obtendo o resultado esperado. Vou tentar atualizar a pergunta para torná-la mais clara.
Hyangelo 5/07
Se o autor da pergunta apenas deseja encontrar nomes de arquivos, o grep não deve ser 'grep -l -v'?
precisa
ele está procurando por conteúdos específicos nos arquivos .java *
lornix
xargs -0 grep -v "something something"deve ser xargs -0 grep -v "something something" /dev/nullcaso contrário você terá resultados estranhos quando find não produz arquivos correspondentes.
22612 James Youngman
{Sorrir} Sim, em algum lugar a lógica ficou toda peluda. Nada como um teste múltiplo de lógica falsa inversa para fazer sua cabeça doer.
Lornix 6/07
4

O computador está sendo um computador: está fazendo o que você mandou, em vez do que você queria que ele fizesse.

grep -v "something something"imprime todas as linhas que não contêm something something. Por exemplo, ele imprime duas linhas entre as três seguintes:

hello world
this is something something
something else

Para imprimir arquivos que não contêm extends SomethingSomethingnenhum lugar, use a -Lopção:

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

Algumas versões do grep não têm a -Lopção (não é especificada pelo POSIX ). Se o seu não for, imprima nada e use o código de retorno para que o shell de chamada faça o que deve ser feito.

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

Como alternativa, use 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 }
'

No Linux ou Cygwin (ou outro sistema com GNU grep), você não precisa usá-lo find, pois grepé capaz de se repetir.

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

Se seu shell for ksh, bash ou zsh, você poderá fazer com que o shell faça o nome do arquivo correspondente. No bash, execute set -o globstarprimeiro (você pode colocar isso no seu ~/.bashrc).

grep -L -E 'extends[[:space:]]+SomethingSomething' **/*.java
Gilles 'SO- parar de ser mau'
fonte
Uau, isso é ainda melhor. Eu estava usando 'extends (/ s) + SomethingSomething' que parecia funcionar até onde eu sabia. Existe alguma diferença nessa sintaxe com a especificada na versão Extended RegEx?
Hyangelo 06/07/12
@ Hyangelo \sé uma extensão GNU grep, que eu acho que é sinônimo [[:space:]].
Gilles 'SO- stop be evil'