Qual é mais eficiente para localizar quais arquivos em um sistema de arquivos inteiro contêm uma string: grep recursivo ou find with grep em uma instrução exec? Suponho que find 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ê conhece apenas -type f, o 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" {} \;

Comentários

  • Matemática / ciência da computação / eficiência do algoritmo em ‘ t opinião com base.
  • Marque este. Embora não seja recursivo, daria um entendimento sobre o que é melhor. unix.stackexchange.com/questions/47983/…
  • @AvinashRaj ele ‘ não está pedindo opinião. Ele ‘ ‘ está perguntando qual é mais eficiente e / ou mais rápido , não qual é ” melhor “. Esta é uma pergunta perfeitamente respondível que tem uma resposta única e específica que depende de como esses dois programas fazem seu trabalho e do que exatamente você fornece para pesquisar.
  • Observe que -exec {} + form fará menos bifurcações, então deve ser mais rápido do que -exec {} \;. Pode ser necessário adicionar -H (ou -h) às opções grep para obter exatamente saída equivalente.
  • Você provavelmente não ‘ queria a opção -r em grep para o segundo

Resposta

Não tenho certeza:

grep -r -i "the brown dog" /* 

é realmente o que você quis dizer. Isso significaria grep recursivamente em todos os arquivos e diretórios não ocultos em / (mas ainda olhe dentro dos arquivos e diretórios ocultos).

Supondo que você quisesse dizer:

grep -r -i "the brown dog" / 

Algumas coisas a serem observadas:

  • Nem todas as grep implementações suportam -r. E entre aqueles que o fazem, os comportamentos são diferentes: 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 até mesmo rodar em loops infinitos), alguns não. Alguns vão olhar dentro dos arquivos do dispositivo (e vai levar algum tempo em /dev/zero por exemplo) ou canais ou arquivos binários …, outros não.
  • É eficiente, pois grep começa a procurar dentro dos arquivos assim que os descobre. Mas, enquanto procura em um arquivo, não está mais procurando por mais arquivos para pesquisar (o que é provavelmente tão bom na maioria dos casos)

Seu:

find / -type f -exec grep -i "the brown dog" {} \; 

(removeu o -r que não fazia sentido aqui) é terrivelmente ineficiente porque você está executando um grep por arquivo. ; deve ser usado apenas para comandos que aceitam apenas um argumento. Além disso, aqui, como grep olha apenas em um arquivo, ele não imprimirá o nome do arquivo, então você “não saberá onde estão as correspondências.

Você” não está procurando dentro de arquivos de dispositivo, canais, links simbólicos …, você não está seguindo links simbólicos, mas ainda está potencialmente olhando dentro de coisas como /proc/mem.

find / -type f -exec grep -i "the brown dog" {} + 

seria muito melhor porque o mínimo possível de grep comandos seriam executados. Você pode obter o nome do arquivo, a menos que a última execução tenha apenas um arquivo. Para isso, é melhor usar:

find / -type f -exec grep -i "the brown dog" /dev/null {} + 

ou com GNU grep:

find / -type f -exec grep -Hi "the brown dog" {} + 

Observe que grep não será iniciado até find encontrou arquivos suficientes para mastigar, portanto, haverá um atraso inicial. E find não continuará pesquisando por mais arquivos até que o grep anterior seja retornado. Alocar e passar a lista de arquivos grandes tem algum impacto (provavelmente insignificante), portanto, no geral, provavelmente será menos eficiente do que um grep -r que não segue o link simbólico ou parece dentro dos dispositivos.

Com ferramentas GNU:

find / -type f -print0 | xargs -r0 grep -Hi "the brown dog" 

Como acima, tão poucos grep as instâncias possíveis serão executadas, mas find continuará procurando por mais arquivos enquanto a primeira grep invocação está procurando dentro do primeiro lote. Isso pode ou não ser uma vantagem.Por exemplo, com dados armazenados em discos rígidos rotativos, find e grep acessar dados armazenados em locais diferentes no disco tornará o disco mais lento rendimento, fazendo com que a cabeça do disco se mova constantemente. Em uma configuração RAID (onde find e grep podem acessar discos diferentes) ou em SSDs, isso pode fazer uma diferença positiva.

Em uma configuração RAID, executar várias invocações simultâneas grep também pode melhorar as coisas. Ainda com ferramentas GNU em armazenamento RAID1 com 3 discos,

find / -type f -print0 | xargs -r0 -P2 grep -Hi "the brown dog" 

pode aumentar o desempenho significativamente. Observe, entretanto, que o segundo grep só será iniciado depois que arquivos suficientes forem encontrados para preencher o primeiro grep comando. Você pode adicionar uma opção -n a xargs para que isso aconteça mais cedo (e passar menos arquivos por grep invocação).

Observe também que se você “estiver redirecionando a saída xargs para qualquer coisa que não seja um dispositivo de terminal, o greps s começarão a armazenar em buffer sua saída, o que significa que a saída desses grep s provavelmente será intercalada incorretamente. Você “teria que usar stdbuf -oL (quando disponível como no GNU ou FreeBSD) neles para contornar isso (você ainda pode ter problemas com linhas muito longas (normalmente> 4KiB)) ou fazer com que cada um escreva sua saída em um arquivo separado e concatene-os todos no final.

Aqui, a string que você está procurando é corrigida (não uma regexp), portanto, usar a opção -F pode fazer a diferença (improvável, pois grep implementações já sabem como otimizar isso).

Outra coisa que pode Faria uma grande diferença fixar a localidade em C se você “estiver em uma localidade multibyte:

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog" 

Para evitar olhar dentro /proc, /sys …, use -xdev e especifique os sistemas de arquivos que deseja pesquisar:

LC_ALL=C find / /home -xdev -type f -exec grep -i "the brown dog" /dev/null {} + 

Ou remova os caminhos que deseja excluir explicitamente:

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \ -type f -exec grep -i "the brown dog" /dev/null {} + 

Comentários

  • Eu não ‘ suponho que alguém pode me apontar um recurso – ou explicar – o que {} e + significam. Não há ‘ nada que eu possa ver nas páginas de manual de exec, grep ou find na caixa Solaris i ‘ que estou usando. É apenas o shell concatenando nomes de arquivos e passando-os para grep?
  • @Poldie, que ‘ é explicado claramente na descrição do -exec predicado na página do manual do Solaris
  • Ah, sim. Não estava ‘ escapando do meu {char enquanto procurava na página do manual. Seu link é melhor; Acho as páginas do manual terríveis de ler.
  • RAID1 com 3 discos? Que estranho …
  • @tink, sim RAID1 em 2 ou mais discos. Com 3 discos em comparação com 2 discos, você aumenta a redundância e o desempenho de leitura, enquanto o desempenho de gravação é praticamente o mesmo. Com 3 discos em oposição a 2, isso significa que você também pode corrigir erros, como quando um bit vira em uma das cópias, você ‘ é capaz de dizer qual é a correta verificando todos 3 cópias enquanto com 2 discos, você pode ‘ t realmente dizer.

Resposta

Se a * na grep chamada não for importante para você, então a primeira deve ser mais eficiente como apenas uma instância de grep é iniciada e os garfos não estão livres. Na maioria dos casos, será mais rápido mesmo com o *, mas em casos extremos a classificação pode reverter isso.

Pode haver outras findgrep estruturas que funcionam melhor, especialmente com muitas estruturas pequenas . Ler grandes quantidades de entradas de arquivo e inodes de uma vez pode melhorar o desempenho da mídia rotativa.

Mas vamos dar uma olhada nas estatísticas do syscall:

find

> strace -cf find . -type f -exec grep -i -r "the brown dog" {} \; % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 97.86 0.883000 3619 244 wait4 0.53 0.004809 1 9318 4658 open 0.46 0.004165 1 6875 mmap 0.28 0.002555 3 977 732 execve 0.19 0.001677 2 980 735 stat 0.15 0.001366 1 1966 mprotect 0.09 0.000837 0 1820 read 0.09 0.000784 0 5647 close 0.07 0.000604 0 5215 fstat 0.06 0.000537 1 493 munmap 0.05 0.000465 2 244 clone 0.04 0.000356 1 245 245 access 0.03 0.000287 2 134 newfstatat 0.03 0.000235 1 312 openat 0.02 0.000193 0 743 brk 0.01 0.000082 0 245 arch_prctl 0.01 0.000050 0 134 getdents 0.00 0.000045 0 245 futex 0.00 0.000041 0 491 rt_sigaction 0.00 0.000041 0 246 getrlimit 0.00 0.000040 0 489 244 ioctl 0.00 0.000038 0 591 fcntl 0.00 0.000028 0 204 188 lseek 0.00 0.000024 0 489 set_robust_list 0.00 0.000013 0 245 rt_sigprocmask 0.00 0.000012 0 245 set_tid_address 0.00 0.000000 0 1 uname 0.00 0.000000 0 245 fchdir 0.00 0.000000 0 2 1 statfs ------ ----------- ----------- --------- --------- ---------------- 100.00 0.902284 39085 6803 total 

grep only

> strace -cf grep -r -i "the brown dog" . % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 40.00 0.000304 2 134 getdents 31.71 0.000241 0 533 read 18.82 0.000143 0 319 6 openat 4.08 0.000031 4 8 mprotect 3.29 0.000025 0 199 193 lseek 2.11 0.000016 0 401 close 0.00 0.000000 0 38 19 open 0.00 0.000000 0 6 3 stat 0.00 0.000000 0 333 fstat 0.00 0.000000 0 32 mmap 0.00 0.000000 0 4 munmap 0.00 0.000000 0 6 brk 0.00 0.000000 0 2 rt_sigaction 0.00 0.000000 0 1 rt_sigprocmask 0.00 0.000000 0 245 244 ioctl 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 execve 0.00 0.000000 0 471 fcntl 0.00 0.000000 0 1 getrlimit 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 1 futex 0.00 0.000000 0 1 set_tid_address 0.00 0.000000 0 132 newfstatat 0.00 0.000000 0 1 set_robust_list ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000760 2871 466 total 

Comentários

  • Na escala de pesquisa de um sistema de arquivos inteiro, os bifurcações são insignificantes. E / S é o que você deseja reduzir.
  • Embora seja um erro do OP, a comparação está incorreta, você deve remover o -r sinalizador de grep ao usar find. Você pode ver que ele pesquisou continuamente os mesmos arquivos, comparando o número de open ocorridos.
  • @qwertzguy, não, o -r deve ser inofensivo, já que -type f garante que nenhum dos argumentos sejam diretórios. Os múltiplos open() s são mais prováveis de outros arquivos abertos por grep em cada invocação (bibliotecas, dados de localização …) ( obrigado pela edição em minha resposta btw)

Resposta

Se você estiver em um SSD e procurar tempo for insignificante, você pode usar GNU parallel:

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} " 

Isso executará até 8 processos grep ao mesmo tempo com base em find encontrado.

Isso irá destruir uma unidade de disco rígido, mas um SSD deve lidar muito bem com isso.

Resposta

Mais uma coisa a se considerar sobre isso é o seguinte.

Algum dos diretórios que grep terá que passar recursivamente conterá mais arquivos do que a configuração nofile do seu sistema? (por exemplo, número de identificadores de arquivos abertos, o padrão é 1024 na maioria das distros Linux)

Se sim, então find é definitivamente o caminho a seguir, já que certas versões do grep explodirá com um erro Lista de argumentos muito longa quando atingir um diretório com mais arquivos do que o máximo de arquivos abertos lida com a configuração.

Apenas meus 2 ¢.

Comentários

  • Por que grep explodir? Pelo menos com GNU grep se você fornecer um caminho com / e usar -R it ‘ Vou simplesmente iterar pelos diretórios. O shell não ‘ não vai expandir nada, a menos que você forneça shell-globs. Portanto, no exemplo dado (/*) apenas o conteúdo da / matéria, não das subpastas que serão simplesmente enumeradas por grep, não passado como argumento do shell.
  • Bem, considerando que o OP estava perguntando sobre a pesquisa recursiva (por exemplo, ” grep -r -i ‘ o cachorro marrom ‘ / * “), eu vi GNU ‘ s grep (pelo menos Versão 2.9) bombar out com: ” -bash: / bin / grep: Lista de argumentos muito longa ” usando a pesquisa exata que o OP usou em um diretório que tinha mais de 140.000 subdiretórios.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *