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 quetime 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 nofind
resultado, enquanto a correspondência comfind -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 significavafind -name filename
. Comfind filename
, apenasfilename
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
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 chamadojack
, ou todos os nomes no diretório se ‘ for um diretório. É ‘ um mal-entendido sobre comofind
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 defind
…) - @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 lentofind
? 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.
find filename
retornaria apenasfilename
sefilename
não fosse do tipo diretório (ou fosse do tipo de diretório, mas não tinha nenhuma entrada em si)