Existe uma maneira mais simples de grep todos os arquivos em um diretório?

21

Quando quero pesquisar em toda uma árvore algum conteúdo, uso

find . -type f -print0 | xargs -0 grep <search_string>

Existe uma maneira melhor de fazer isso em termos de desempenho ou brevidade?

Dancrumb
fonte
2
@ Downowner: Feliz em melhorar esta questão, se você puder compartilhar suas preocupações.
Dancrumb
2
muitas versões de busca possuem xargs embutidas: find. -type f -exec fgrep <search_string> {} +
simpleuser

Respostas:

42

Verifique se a sua opção de grepsuporte -r(para recursão ):

grep -r <search_string> .
Philippos
fonte
1
Sim ... Acabei de encontrar stackoverflow.com/questions/16956810/… e essa é a resposta também.
Dancrumb
adicione um comentário --exclude-dirpara abordar o desempenho e temos um vencedor!
Dancrumb
1
Apenas observe que isso não é portátil, no entanto, grepnas recentes distribuições do FreeBSD e Linux o suportam. E por que --exclude-dir? Você não pediu para procurar uma árvore inteira ?
Philippos
Ponto justo ... --exclude-diré realmente útil no meu caso de uso (porque partes da subárvore são grandes, mas inúteis) e perguntei sobre desempenho ... mas você está certo, não é necessário.
Dancrumb
Nesse caso, devo acrescentar que o IIRC --exclude-diré exclusivo do GNU grep. (-:
Philippos
13

Uma resposta subótima: em vez de canalizar a saída para findinto grep, você pode simplesmente executar

find . -type f -exec grep 'research' {} '+'

e voila, um comando em vez de dois!

explicação:

find . -type f

encontre todos os arquivos regulares dentro.

-exec grep 'research'

grep 'pesquisa'

{}

no nome do arquivo encontrado

'+'

use um comando por todos os nomes de arquivos, não uma vez por nome de arquivo.

Nota: com ';'isso teria sido uma vez por nome de arquivo.

Fora isso, se você usar isso para processar o código-fonte, poderá pesquisar o ackque é feito para procurar bits de código facilmente.

ack

Editar:

Você pode estender um pouco essa pesquisa. Primeiro, você pode usar a -name ''opção de findpara procurar arquivos com padrão de nomeação específico.

Por exemplo :

  • somente arquivos que correspondem aos logs: -name '*.log'

  • apenas arquivos que correspondem aos cabeçalhos c, mas você não pode usar letras maiúsculas ou minúsculas nas extensões do seu nome de arquivo: -iname *.c

Nota: como para grepe ack, a -iopção significa insensível a maiúsculas e minúsculas neste caso.

Nesse caso, o grep será exibido sem cor e sem números de linha.

Você pode mudar isso com o --colore os -ninterruptores (números de cor e de linhas em arquivos respectivamente).

No final, você pode ter algo como:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

por exemplo

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello
Pierre-Antoine Guillaume
fonte
5
acké grande, e uma versão mais rápida acké ag(o pesquisador prata, geoff.greer.fm/ag )
cfeduke
1
Eu prefiro isso com filtro como -name '*.log'é mais rápido.
Sdkks
@cfeduke eu não tentei, principalmente porque ag não é parte de repositórios apt padrão em WSL (você tem que trabalhar com o que você tem!)
Pierre-Antoine Guillaume
Um truque é adicionar / dev / null ao grep para que o nome do arquivo apareça.
ChuckCottrill 18/08/19
Um truque é procurar apenas diretórios e, em seguida, -exec grep / dev / null {} / * para obter todos os arquivos com um único fork / exec por diretório.
ChuckCottrill 18/08/19
12

Se você deseja recursar em subdiretórios:

grep -R 'pattern' .

A -Ropção não é uma opção padrão, mas é suportada pelas grepimplementações mais comuns .

Kusalananda
fonte
7
Use -rem vez de -Rpular ligações simbólicas ao GNU grep está em questão
αғsнιη
1
@AFSHIN Por que você não gostaria de seguir links simbólicos?
Kusalananda
4
Recursão @Kusalananda? Embora as grepimplementações atuais do GNU capturem recursões, eu acho. Caso contrário, depende do que você quer dizer com "árvore".
Philippos
2
@ Phipippos IMHO, cuidar do usuário não é algo que uma ferramenta como grepdeve fazer. Se o usuário tem laços link simbólico em sua estrutura de diretório, bem, isso é problema do usuário :-)
Kusalananda
3
@Kusalananda E se o sistema forneceu o loop? Nunca me perdi em /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI como ferramentas de babá para mim (a menos que elas forneçam magia estranha que chamam de "AI"). (-;
Philippos
5

Como observado acima, -rou -R(dependendo do tratamento do link simbólico desejado) é uma opção rápida.

No entanto, -d <action>pode ser útil às vezes.

O interessante -dé o comando skip, que silencia o "grep: directory_name: Is a directory" quando você deseja apenas verificar o nível atual.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

e claro:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

A -d skipopção é REALMENTE útil dentro de outro script para que você não precise 2> /dev/null. :)

Petro
fonte
0

Se você estiver lidando com muitos arquivos, o grep será executado mais rapidamente se você remover os arquivos que eles precisam pesquisar, em vez de grep todos os arquivos em subpastas.

Eu uso esse formato algumas vezes:

grep "primary" `find . | grep cpp$`

Encontre todos os arquivos nas subpastas .desse fim em cpp. Em seguida, grep esses arquivos para "primário".

Se desejar, você pode continuar canalizando esses resultados para outras chamadas grep:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"
Rudy
fonte
1
backtics não são uma boa prática moderna, eles são todos, mas obsoleto
Christopher
1
Isso será interrompido se você tiver arquivos com caracteres especiais em seus nomes. Eu não sei o quão especial elas precisam ser para serem especiais demais para que isso funcione como está, mas o que você está fazendo é realmente a mesma coisa que analisar a saída de ls, o que também é ruim.
um CVn