Como ignorar certos nomes de arquivos usando “find”?

112

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 dele para o SearchString especificado. Como desenvolvedor, isso vem a calhar às vezes.

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

A página MAN para encontrar o tipo de me confundiu embora. Eu tentei usar -prune, e isso me deu um comportamento estranho. Em uma tentativa de pular apenas as páginas .html (para começar), tentei:

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

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

Obrigado

    
por Cody S 06.03.2012 / 00:28

3 respostas

159

Você pode usar o recurso negate (!) do find para não corresponder 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.

    
por 06.03.2012 / 01:40
9

Eu tive o mesmo problema por um longo tempo e existem várias soluções que podem ser aplicadas em diferentes situações:

  • ack-grep é uma espécie de " grep " do desenvolvedor, que por padrão ignora diretórios de controle de versão e arquivos temporários. A página man explica como pesquisar apenas tipos de arquivos específicos e como definir seus próprios .
  • As opções grep e --exclude do --exclude-dir podem ser usadas com muita facilidade para ignorar os diretórios globs e single (sem globbing para diretórios, infelizmente). / li>
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... deve funcionar, mas as opções acima são provavelmente menos trabalhosas a longo prazo.
por 06.03.2012 / 14:54
7

O comando find a seguir remove diretórios cujos nomes contêm .svn , Embora não caia no diretório, o nome do caminho removido é impresso ... ( -name '*.svn' é o causa!) ..

Você pode filtrar os nomes dos diretórios por meio de: grep -d skip , que silenciosamente ignora esses "nomes de diretório" de entrada.

Com o GNU grep, você pode usar -H em vez de /dev/null . Como um problema secundário: \+ pode ser muito mais rápido que \; , por exemplo. para 1 milhão de arquivos de uma linha, usando \; , 4m20s , usando \+ , foi necessário apenas 1.2s .

O método a seguir usa xargs em vez de -exec e supõe que não há novas linhas de código \n em nenhum dos seus nomes de arquivos . Conforme usado aqui, xargs é praticamente o mesmo que \+ de find.

xargs pode passar nomes de arquivos que contêm espaços consecutivos alterando o delimitador de entrada para '\n' com a opção -d .

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

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'
    
por 06.03.2012 / 04:29

Tags