Questão Como ignorar certos nomes de arquivos usando “find”?


Um dos meus comandos BASH favoritos é:

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

que procura o conteúdo de todos os arquivos em e abaixo do diretório atual 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 fazer este comando BASH ainda mais avançado, não procurando quaisquer arquivos que estão dentro ou abaixo de um diretório que contenha ".svn", ou quaisquer arquivos que terminar com ".html"

A página do MAN para encontrar 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), eu tentei:

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

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

obrigado


110


origem


Apenas fyi: find não é um comando bash embutido, mas um programa separado - WakiMiko
Você pode pesquisar dentro do arquivo com grep -rl 'SearchString' - emanuele
@emanuele Olá, bem vindo ao SuperUser (e à rede Stack Exchange). Esta é uma pergunta que fiz e que foi respondida há dois anos e meio. Normalmente, se você quiser adicionar uma resposta à pergunta, faça isso rolando para baixo e respondendo lá, em vez de em um comentário. Como essa pergunta já tem 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
Oi, isso não é uma resposta para sua pergunta. É apenas uma dica, como você afirmou no preâmbulo que usa find para pesquisar dentro de um arquivo. - emanuele
FWIW, -name '*.*' não encontra todos arquivos: somente aqueles com . em seu nome (o uso de *.* é tipicamente um DOS-ismo, enquanto no Unix, você normalmente usa apenas * por isso). Para realmente combinar com todos eles, apenas remova o argumento completamente: find . -exec .... Ou se você quiser aplicar somente o grep aos arquivos (e pular diretórios), então faça find . -type f -exec .... - Stefan


Respostas:


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.


157



Devo ainda especificar -name '.'em algum lugar lá? Eu faria isso antes ou depois das negações? - Cody S
Foi a intenção do seu *.* jogo para garantir que apenas correspondam arquivos contendo um .? Encontrar irá corresponder a todos os arquivos na ausência de um name diretiva, então o acima irá corresponder a tudo, exceto html e svn - Paul
Eu acho que você quer -wholename '*.svn*' ao invés de -name. - fuenfundachtzig
Sim, isso faz, para que o .svn diretórios são excluídos dos resultados da pesquisa. - fuenfundachtzig
@Nomenon ! -name '.' deve excluir . dos resultados da pesquisa. - Paul


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

  • ack-grep é uma espécie de "desenvolvedor grep" qual por padrão ignora diretórios de controle de versão e arquivos temporários. o man página explica como procurar apenas tipos de arquivos específicos e como defina seu próprio.
  • greppor conta própria --exclude e --exclude-dir opções podem ser usadas com muita facilidade para pular o arquivo globs e solteiro diretórios (sem globbing para diretórios, infelizmente).
  • 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.

9





Os seguintes find comando remove diretórios cujos nomes conter  .svn, Embora não desça ao diretório, o nome do caminho removido é impresso ... (-name '*.svn' é a causa!) ..

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

Com o GNU grep, você pode usar -H ao invés de /dev/null. Como uma ligeira questão lateral: \+ pode ser muito mais rápido que \;, por exemplo. para 1 milhão de arquivos de uma linha, usando \; levou 4m20susando \+ levou apenas 1.2s.

O método a seguir usa xargs ao invés de -exece assume que não há novas linhas \n em qualquer um dos seus arquivos nomes. Como usado aqui, xargs é o mesmo que o de Find \+.

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

Isso exclui diretórios cujos nomes conter  .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'

7



Obrigado por apontar o \+ variante da ação -exec. Hooray para problemas laterais ligeiros! - Christian Long
Claro, desde + não é um caractere especial para o shell, você não precisa digitar \ antes disso. - Scott