Por que o comando “find | grep 'filename' ”muito mais lento que 'find' filename '”?

8

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

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

    
por yoyo_fun 03.10.2017 / 12:04

5 respostas

11

(estou assumindo o% GNUfind aqui)

Usando apenas

find filename

seria rápido, porque apenas retornaria filename , ou os nomes dentro de filename se fosse um diretório, ou um erro se esse nome não existisse 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 find gerar uma lista de todos nomes do diretório atual e abaixo, que grep filtraria. Esta obviamente seria uma operação muito mais lenta.

Suponho que o que era realmente pretendido era

find . -type f -name 'filename'

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

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

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

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

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

Quando você diz

find a b c

você solicita que find liste todos os nomes disponíveis nos três caminhos a , b e c . Se estes 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 faço

find . -type f -name 'filename'

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

Exemplo:

O seguinte parece "encontrar" o arquivo chamado .profile no meu diretório pessoal:

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

Mas, na verdade, apenas retorna todos os nomes no caminho .profile (existe apenas um nome e esse é o arquivo).

Então, eu cd acima de um nível e tente novamente:

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

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

No entanto, se eu der uma olhada no diretório atual e, em seguida, restringir os nomes retornados a apenas .profile , ele também será encontrado lá:

$ pwd
/home
$ find . -name '.profile'
./kk/.profile
    
por 03.10.2017 / 12:56
1

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

Como para Kusalananda, a chamada find | grep é claramente mais rápida no meu sistema, o que não faz muito sentido. No começo, assumi algum tipo de problema de buffering; que escrever no console reduz o tempo para o próximo syscall para ler o próximo nome de arquivo. Escrever para um pipe é muito rápido: cerca de 40MiB / s, mesmo para gravações de 32 bytes (no meu sistema bastante lento; 300 MiB / s para um tamanho de bloco de 1MiB). Assim, eu assumi que find pode ler o sistema de arquivos mais rápido ao gravar em um pipe (ou arquivo) para que as duas operações lendo caminhos de arquivo e gravando no console pudessem rodar em paralelo (que find como um único processo de thread não pode fazer sozinho.

A culpa é de find

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

mostra que find faz algo incrivelmente estúpido (o que quer que seja). Ele acaba por ser bastante incompetente na execução de -name '*.txt' .

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

Você pode pensar que find -name vence se houver muito pouco para escrever. Mas só fica mais embaraçoso para find . Ele perde mesmo que não haja nada para gravar em arquivos de 200K (13M de dados de pipe) 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. Use um regex e o problema desapareceu:

:> time find "$HOME"/ -regex '\.txt$' >/dev/null     

real    0m0.679s
user    0m0.264s
sys     0m0.410s

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

    
por 03.10.2017 / 15:01
1

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

    
por 04.10.2017 / 15:15
0

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

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

Então, quando você pedir a find para localizar um arquivo cujo nome requeira apenas checagem, find irá pedir para esse arquivo, e somente esse arquivo, para o sistema de arquivos subjacente, que lerá muito poucas páginas do armazenamento em massa. Portanto, se o sistema de arquivos vale a pena, essa operação será executada muito mais rapidamente do que percorrendo a árvore inteira para recuperar todas as entradas.

Quando você pede por find no entanto é exatamente isso que você faz, você percorre toda a árvore, lendo. Cada. Solteiro. Entrada. Com diretórios grandes, isso pode ser um problema (é exatamente o motivo pelo qual vários softwares, precisando armazenar muitos arquivos em disco, criarão "árvores de diretórios" com dois ou três componentes de profundidade: assim, cada folha precisa conter menos arquivos).

    
por 03.10.2017 / 15:26
-2

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

find / stones

find irá comparar 'beatles' a 'stones' e soltar quando 's' e 'b' não corresponderem.

find / | grep stones

Neste caso, o find passará '/ john / paul / george / ringo / beatles' para que o grep e o grep tenham que percorrer todo o caminho antes de determinar se é uma correspondência.

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

    
por 03.10.2017 / 13:53