Eu tentei os dois comandos e o comando find | grep "filename" é muitas vezes mais lento do que o simples .

Qual seria uma explicação adequada para esse comportamento?

Comentários

  • Você estão listando todos os arquivos com find e, em seguida, passando os dados para o grep processar. Com find usado nele ‘ s, você está perdendo a etapa de passar todos os arquivos listados para o grep para analisar a saída. Portanto, será mais rápido.
  • Mais lento em que sentido? Os comandos demoram um tempo diferente para serem concluídos?
  • Não posso ‘ reproduzir isso localmente. Se houver alguma coisa, time find "$HOME" -name '.profile' relata um tempo maior do que time find "$HOME" | grep -F '.profile'. (17s x 12s).
  • @JenniferAnderson Corri os dois repetidamente. Os 17 e 12 segundos são médias. E sim, a variação grep corresponderá a qualquer lugar no find resultado, enquanto a correspondência com find -name corresponderia apenas exatamente (neste caso).
  • Sim, find filename seria rápido . Eu meio que presumi que era um erro de digitação e que OP significava find -name filename. Com find filename, apenas filename seria examinado (e nada mais).

Resposta

(Presumo que GNU find aqui)

Usando apenas

find filename 

seria rápido, porque retornaria apenas filename ou os nomes dentro de filename se for “um diretório, ou um erro se esse nome não existir no diretório atual. É uma operação muito rápida, semelhante a ls filename (mas recursiva se filename for um diretório).

Em contraste,

find | grep filename 

permitiria a find gerar uma lista de todos nomes de o diretório atual e abaixo, que grep filtraria. Esta seria obviamente uma operação muito mais lenta.

Estou assumindo que o que foi na verdade o pretendido era

find . -type f -name "filename" 

Isso procuraria filename como o nome de um arquivo regular em qualquer lugar em o diretório atual ou abaixo.

Isso será tão rápido (ou comparativamente rápido) quanto find | grep filename, mas o grep solução corresponderia filename ao caminho completo de cada nome encontrado, de forma semelhante ao que -path "*filename*" faria com find.


A confusão vem de um mal-entendido de como find funciona.

O utilitário pega vários caminhos e retorna todos os nomes abaixo desses caminhos.

Você pode então restrinja os nomes retornados usando vários testes que podem atuar no nome do arquivo, o caminho, o carimbo de data / hora, o tamanho do arquivo, o tipo de arquivo, etc.

Quando você diz

find a b c 

você pede a find para listar todos os nomes disponíveis nos três caminhos a, b e c. Se esses forem nomes de arquivos regulares no diretório atual, eles serão retornados. Se algum deles for o nome de um diretório, ele será retornado junto com todos os outros nomes dentro desse diretório.

Quando eu faço

find . -type f -name "filename" 

Isso gera uma lista de todos os nomes no diretório atual (.) e abaixo. Em seguida, ele restringe os nomes aos de arquivos regulares, ou seja, não de diretórios, etc., com -type f. Então, há uma restrição adicional para nomes que correspondam a filename usando -name "filename". A string filename pode ser um padrão global de nome de arquivo, como *.txt (lembre-se de citá-lo!).

Exemplo:

O seguinte parece “encontrar” o arquivo chamado .profile em meu diretório inicial:

$ pwd /home/kk $ find .profile .profile 

Mas, na verdade, ele apenas retorna todos os nomes no caminho .profile (há apenas um nome, e este é deste arquivo).

Então eu cd subo um nível e tento novamente:

$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory 

O find agora não pode encontrar nenhum caminho chamado .profile.

No entanto, se eu conseguir examinar o diretório atual e restringir os nomes retornados a apenas .profile , ele encontrará a partir daí também:

$ pwd /home $ find . -name ".profile" ./kk/.profile 

Comentários

  • find filename retornaria apenas filename se filename não fosse do tipo diretório (ou fosse do tipo de diretório, mas não tinha nenhuma entrada em si)

Resposta

Explicação não técnica: Procurando Jack no meio da multidão é mais rápido do que procurar por todos na multidão e eliminar todos da consideração, exceto Jack.

Comentários

  • O problema é que o OP espera que Jack seja a única pessoa na multidão. Se for, eles ‘ têm sorte. find jack listará jack se ‘ um arquivo chamado jack, ou todos os nomes no diretório se ‘ for um diretório. É ‘ um mal-entendido sobre como find funciona.

Resposta

Ainda não entendi o problema, mas posso fornecer mais alguns insights.

Como para Kusalananda, a find | grep chamada é claramente mais rápido no meu sistema, o que não faz muito sentido. No início, presumi algum tipo de problema de buffer; que a gravação no console diminui o tempo para a próxima chamada de tela para a leitura do próximo nome de arquivo. Escrever em um pipe é muito rápido: cerca de 40 MiB / s, mesmo para gravações de 32 bytes (no meu sistema bastante lento; 300 MiB / s para um tamanho de bloco de 1 MiB). Portanto, presumi que find pode ler do sistema de arquivos mais rápido ao gravar em um canal (ou arquivo) para que as duas operações de leitura de caminhos de arquivo e gravação no console possam ser executadas em paralelo ( que find como um único processo de thread não pode fazer por conta própria.

É “s find “s falha

Comparando as duas chamadas

:> time find "$HOME"/ -name "*.txt" >/dev/null real 0m0.965s user 0m0.532s sys 0m0.423s 

e

:> time find "$HOME"/ >/dev/null real 0m0.653s user 0m0.242s sys 0m0.405s 

mostram que find faz algo incrivelmente estúpido (seja o que for). acabou sendo bastante incompetente na execução de -name "*.txt".

Pode depender da relação de entrada / saída

Você pode pensar que find -name ganha se houver muito pouco para escrever. Mas fica mais embaraçoso para find. Perde mesmo se não houver nada para escrever em arquivos de 200 K (13 MB de dados de canal) para grep:

time find /usr -name lwevhewoivhol 

find pode ser tão rápido quanto grep, embora

Acontece que a estupidez de find “com name não se estende a outros testes. Em vez disso, use um regex e o problema desaparece:

:> time find "$HOME"/ -regex "\.txt$" >/dev/null real 0m0.679s user 0m0.264s sys 0m0.410s 

Acho que isso pode ser considerado um bug. Alguém está disposto a enviar um relatório de bug? Minha versão é find (GNU findutils) 4.6.0

Comentários

  • Quão repetíveis são seus tempos? Se você fez o -name teste primeiro, pode ter sido mais lento devido ao conteúdo do diretório não estar sendo armazenado em cache. (Ao testar -name e -regex, descobri que demoram quase o mesmo tempo, pelo menos depois que o efeito do cache foi levado em consideração. claro que pode ser apenas uma versão diferente de find …)
  • @psmears Claro, eu fiz esses testes várias vezes. O problema de cache foi mencionado até mesmo nos comentários à pergunta antes da primeira resposta. Minha find versão é find (GNU findutils) 4.6.0
  • Por que é surpreendente que adicionar -name '*.txt' torna mais lento find? Ele tem que fazer um trabalho extra, testando cada nome de arquivo.
  • @Barmar Por um lado, esse trabalho extra pode ser feito extremamente rápido. Por outro lado, esse trabalho extra economiza outro trabalho. find precisa gravar menos dados. E escrever em um pipe é uma operação muito mais lenta.
  • Escrever em um disco é muito lento, escrever em um pipe não é tão ruim, apenas copia para um buffer de kernel. Observe que em seu primeiro teste, escrever mais para /dev/null de alguma forma usou menos o tempo do sistema.

Resposta

Aviso : Presumo que você queira dizer find . -name filename (caso contrário, você está procurando coisas diferentes; find filename realmente procura um caminho chamado nome do arquivo , que pode conter quase nenhum arquivo, portanto, saindo muito rapidamente).


Suponha que você tenha um diretório contendo cinco mil arquivos. Na maioria dos sistemas de arquivos, esses arquivos são armazenados em uma estrutura em árvore , que permite localizar rapidamente qualquer arquivo.

Portanto, quando você pedir a find para localizar um arquivo cujo nome apenas requer verificação, find perguntará para aquele arquivo, e apenas aquele arquivo, para o sistema de arquivos subjacente, que lerá muito poucas páginas do armazenamento em massa. Portanto, se o sistema de arquivos valer a pena, esta operação será executada muito mais rápido do que atravessando a árvore inteira para recuperar todas as entradas.

Quando você pede find simples, no entanto, é exatamente o que você faz, você percorre a árvore inteira, lendo. Cada. Única. Entrada. Com grandes diretórios, isso pode ser um problema (é exatamente a razão pela qual vários softwares, precisando armazenar muitos arquivos no disco, criarão “árvores de diretórios” com dois ou três componentes de profundidade: desta forma, cada folha precisa conter apenas menos arquivos) .

Resposta

Vamos supor que o arquivo / john / paul / george / ringo / beatles exista e o arquivo que você está procurando é chamado de “pedras”

find / stones 

O find irá comparar “beatles” a “pedras” e soltará quando o “s” e “b” não corresponderem .

find / | grep stones 

Neste caso, find passará “/ john / paul / george / ringo / beatles” para grep e grep wil Tenho que percorrer todo o caminho antes de determinar se é compatível.

O grep está, portanto, fazendo muito mais trabalho e é por isso que leva mais tempo

Comentários

  • Você já tentou isso?
  • O custo das comparações de strings (extremamente simples e barato) é completamente diminuído pelo custo IO (ou apenas syscall se armazenado em cache) das pesquisas de diretório.
  • grep isn ‘ ta comparação de strings, sua comparação de expressões regulares, o que significa que ele tem que percorrer todo o string até encontrar uma partida ou chega ao fim. As pesquisas de diretório são as mesmas, não importa o quê.
  • @Paranoid Hm, de que versão de find você está falando? Aparentemente, ‘ não é nada parecido com o find que ‘ estou acostumado a fazer no debian.

Deixe uma resposta

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