Como ignorar certos nomes de arquivos usando "find"?


143

Um dos meus comandos BASH favoritos é:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

que pesquisa o conteúdo de todos os arquivos no diretório atual e abaixo do diretório SearchString especificado. Como desenvolvedor, isso às vezes é útil.

No entanto, devido ao meu projeto atual e à estrutura da minha base de código, eu gostaria de tornar esse comando BASH ainda mais avançado, não pesquisando arquivos que estejam dentro ou abaixo de um diretório que contenha ".svn" ou quaisquer arquivos que termine com ".html"

A página MAN para encontrar meio que me confundiu. Eu tentei usar -une, e isso me deu um comportamento estranho. Na tentativa de pular apenas as páginas .html (para iniciar), tentei:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

e não conseguiu o comportamento que eu esperava. Acho que posso estar perdendo o ponto de podar. Vocês poderiam me ajudar?

obrigado


1
Apenas para informação: findnão é um comando bash build-in, mas um programa separado
WakiMiko

1
Você pode pesquisar arquivo dentro comgrep -rl 'SearchString'
emanuele

Olá, seja bem-vindo ao SuperUser (e à rede Stack Exchange). Esta é uma pergunta que eu fiz, e que foi respondida há 2 anos e meio atrás. Normalmente, se você deseja adicionar uma resposta à pergunta, faça isso rolando para baixo e respondendo lá, em vez de em um comentário. Como essa pergunta já possui uma resposta aceita (aquela com a marca de seleção verde), é improvável que sua resposta receba muita atenção. PARA SUA INFORMAÇÃO.
Cody S

1
Olá, não é uma resposta para sua pergunta. É apenas uma dica, como você declarou no preâmbulo, que é usado findpara pesquisar dentro de um arquivo.
Emanuele

2
O FWIW, -name '*.*'não encontra todos os arquivos: apenas aqueles com um .em seu nome (o uso de *.*geralmente é um DOS-ism, enquanto no Unix, você normalmente usa apenas *para isso). Para realmente combiná-los todos, basta remover o argumento completamente: find . -exec .... Ou se você deseja aplicar apenas grep a arquivos (e pular diretórios), faça find . -type f -exec ....
Stefan

Respostas:


197

Você pode usar o recurso negar (!) De localizar para não corresponder aos arquivos com nomes específicos:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

Portanto, se o nome terminar em .html ou contiver .svn em qualquer lugar do caminho, ele não corresponderá e, portanto, o exec não será executado.


1
Ainda devo especificar -name ' . em algum lugar aí? Eu faria isso antes ou depois das negações?
Cody S

A intenção da sua *.*correspondência era garantir que apenas correspondessem arquivos contendo um .? Encontrar irá corresponder a todos os arquivos na ausência de uma namedirectiva, de modo que o acima irá corresponder a tudo, exceto html e svn
Paul

5
Eu acho que você quer -wholename '*.svn*'mais do que -name.
fuenfundachtzig

2
Sim, para que os .svndiretórios sejam excluídos dos resultados da pesquisa.
fuenfundachtzig

1
@Noumenon ! -name '.'deve excluir .dos resultados encontrados.
Paul

11

Eu tive o mesmo problema há muito tempo e existem várias soluções que podem ser aplicáveis ​​em diferentes situações:

  • ack-grepé uma espécie de "desenvolvedor grep" que, por padrão, ignora os diretórios de controle de versão e os arquivos temporários. A manpágina explica como pesquisar apenas tipos de arquivos específicos e como definir seus próprios .
  • grepAs próprias opções --excludee --exclude-dirpodem ser usadas com muita facilidade para ignorar os globs de arquivos e os diretórios únicos (infelizmente não há globs nos diretórios).
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... deve funcionar, mas as opções acima provavelmente são menos problemáticas a longo prazo.

9

O findcomando a seguir remove os diretórios cujos nomes contêm .svn , embora não desça no diretório, o nome do caminho removido é impresso ... ( -name '*.svn'é a causa!) ..

Você pode filtrar os nomes dos diretórios via: grep -d skipque ignora silenciosamente esses "nomes de diretórios" de entrada.

Com o GNU grep, você pode usar em -Hvez de /dev/null. Como um pequeno problema: \+pode ser muito mais rápido do que \;, por exemplo. para 1 milhão de arquivos de uma linha, o uso \;levou 4m20s , o uso \+levou apenas 1,2s .

O método a seguir usa em xargsvez de -exece assume que não há novas linhas \nem nenhum dos seus nomes de arquivo . Como usado aqui, xargsé o mesmo que o de encontrar \+.

xargspode passar nomes de arquivos que contêm espaços consecutivos alterando o delimitador de entrada para '\n'com a -dopção

Isso exclui diretórios cujos nomes contêm .svn e recebem somente arquivos que não terminam .html.

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'

1
Obrigado por apontar a \+variante da ação -exec. Viva para pequenas questões secundárias!
Christian Long

Obviamente, como +não é um caractere especial para o shell, você não precisa digitar \antes dele.
Scott
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.