Qual é mais eficiente para encontrar quais arquivos em um sistema de arquivos inteiro contêm uma sequência: grep recursivo ou encontrar com grep em uma instrução exec? Presumo que encontrar seria mais eficiente, porque você pode pelo menos fazer alguma filtragem se souber a extensão do arquivo ou um regex que corresponda ao nome do arquivo, mas quando você souber apenas o -type f
que é melhor? GNU grep 2.6.3; find (GNU findutils) 4.4.2
Exemplo:
grep -r -i 'the brown dog' /
find / -type f -exec grep -i 'the brown dog' {} \;
-exec {} +
formulário fará menos garfos, portanto deve ser mais rápido que-exec {} \;
. Pode ser necessário adicionar-H
(ou-h
) àsgrep
opções para obter uma saída exatamente equivalente.-r
grep
Respostas:
Não tenho certeza:
é realmente o que você quis dizer. Isso significaria grep recursivamente em todos os arquivos e diretórios não ocultos
/
(mas ainda assim procure dentro de arquivos e diretórios ocultos).Supondo que você quis dizer:
Algumas coisas a serem observadas:
grep
implementações suportam-r
. E entre os que o fazem, os comportamentos diferem: alguns seguem links simbólicos para diretórios ao percorrer a árvore de diretórios (o que significa que você pode acabar procurando várias vezes no mesmo arquivo ou mesmo executar em loops infinitos), outros não. Alguns irão procurar dentro de arquivos de dispositivos (e isso levará algum tempo,/dev/zero
por exemplo) ou tubos ou arquivos binários ..., outros não.grep
começa a procurar dentro de arquivos assim que os descobre. Mas enquanto ele aparece em um arquivo, não está mais procurando mais arquivos para pesquisar (o que provavelmente é tão bom na maioria dos casos)Seu:
(removido o
-r
que não fazia sentido aqui) é terrivelmente ineficiente porque você está executando umgrep
por arquivo.;
deve ser usado apenas para comandos que aceitam apenas um argumento. Além disso, aqui, comogrep
parece apenas em um arquivo, ele não imprimirá o nome do arquivo, portanto você não saberá onde estão as correspondências.Você não está olhando dentro de arquivos de dispositivos, canais, links simbólicos ..., não está seguindo links simbólicos, mas ainda está potencialmente olhando dentro de coisas como
/proc/mem
.seria muito melhor porque o
grep
menor número possível de comandos seria executado. Você obteria o nome do arquivo, a menos que a última execução tenha apenas um arquivo. Para isso, é melhor usar:ou com GNU
grep
:Observe que
grep
não será iniciado atéfind
encontrar arquivos suficientes para mastigar, portanto haverá um atraso inicial. Efind
não continuará pesquisando por mais arquivos até que o anteriorgrep
retorne. Alocar e passar a grande lista de arquivos tem algum impacto (provavelmente desprezível); portanto, em geral, será menos eficiente do que umgrep -r
que não segue o link simbólico ou olha para os dispositivos.Com as ferramentas GNU:
Como acima, o menor número
grep
possível de instâncias será executado, masfind
continuará procurando por mais arquivos enquanto a primeiragrep
chamada estiver dentro do primeiro lote. Isso pode ou não ser uma vantagem. Por exemplo, com os dados armazenados em discos rígidos rotacionaisfind
e ogrep
acesso a dados armazenados em diferentes locais do disco, a velocidade do disco diminuirá a velocidade, fazendo com que a cabeça do disco se mova constantemente. Em uma configuração de RAID (ondefind
egrep
pode acessar discos diferentes) ou em SSDs, isso pode fazer uma diferença positiva.Em uma configuração de RAID, a execução de várias chamadas simultâneas
grep
também pode melhorar as coisas. Ainda com as ferramentas GNU no armazenamento RAID1 com 3 discos,pode aumentar significativamente o desempenho. Observe, no entanto, que o segundo
grep
será iniciado apenas quando forem encontrados arquivos suficientes para preencher o primeirogrep
comando. Você pode adicionar uma-n
opçãoxargs
para que isso aconteça mais cedo (e passar menos arquivos porgrep
chamada).Observe também que, se você estiver redirecionando a
xargs
saída para algo que não seja um dispositivo terminal, osgreps
s começarão a armazenar buffer em sua saída, o que significa que a saída dessesgrep
s provavelmente será intercalada incorretamente. Você precisaria usarstdbuf -oL
(quando disponível, como no GNU ou FreeBSD) neles para solucionar isso (você ainda pode ter problemas com linhas muito longas (normalmente> 4KiB)) ou cada um deles escrever sua saída em um arquivo separado e concatená-los tudo no final.Aqui, a string que você está procurando é fixa (não uma regexp), portanto, o uso da
-F
opção pode fazer a diferença (improvável, pois asgrep
implementações já sabem como otimizar isso).Outra coisa que pode fazer uma grande diferença é fixar o código do idioma em C se você estiver em um código de idioma de vários bytes:
Para evitar olhar para dentro
/proc
,/sys
..., use-xdev
e especifique os sistemas de arquivos nos quais deseja pesquisar:Ou remova os caminhos que você deseja excluir explicitamente:
fonte
-exec
predicado na página homem SolarisSe o
*
nagrep
chamada não é importante para você, em seguida, a primeira deve ser mais eficiente como apenas uma instânciagrep
é iniciada, e garfos não são livres. Na maioria dos casos, será mais rápido, mesmo*
nos casos extremos, mas a classificação pode reverter isso.Pode haver outro
find
-grep
estruturas que funcionam melhor, especialmente com muitos arquivos pequenos. A leitura de grandes quantidades de entradas e inodes de arquivos ao mesmo tempo pode melhorar o desempenho da mídia rotativa.Mas vamos dar uma olhada nas estatísticas do syscall:
encontrar
somente grep
fonte
-r
sinalizadorgrep
ao usá-lofind
. Você pode ver que ele procurou repetidamente os mesmos arquivos comparando o númeroopen
disso.-r
deve ser inofensivo, pois as-type f
garantias de que nenhum dos argumentos são diretórios. As múltiplasopen()
s são mais prováveis para baixo para os outros arquivos abertos porgrep
em cada invocação (bibliotecas, dados de localização ...) (obrigado pela edição em minha resposta btw)Se você estiver em um SSD e o tempo de busca for insignificante, você pode usar o GNU paralelo:
Isso executará até 8 processos grep ao mesmo tempo, com base no que foi
find
encontrado.Isso atrapalha uma unidade de disco rígido, mas um SSD deve lidar muito bem com ela.
fonte
Mais uma coisa a considerar sobre este é o seguinte.
Algum dos diretórios que o grep precisará percorrer recursivamente conterá mais arquivos do que a configuração de nofile do sistema ? (por exemplo, número de identificadores de arquivos abertos, o padrão é 1024 na maioria das distribuições Linux)
Se assim for, então encontrar é definitivamente o caminho a percorrer uma vez que certas versões do grep vai bombardear com uma lista de argumentos muito longa de erro quando se atinge um diretório com mais arquivos do que o máximo de arquivo aberto ajuste lida.
Apenas meus 2 ¢.
fonte
grep
explodiria? Pelo menos com o GNU grep, se você der um caminho com trailing/
e usá--R
lo, ele simplesmente percorrerá os diretórios. O shell não vai expandir nada, a menos que você dê globs de shell. Portanto, no exemplo dado (/*
), apenas o conteúdo da/
matéria, não as subpastas que serão simplesmente enumeradas porgrep
, não é passado como argumento do shell.