A razão pela qual o comando find é lento
Essa é uma questão realmente interessante ... ou, honestamente, mallicious :
O comando
find . -mindepth 2 -mtime +5 -print -delete
é muito diferente da variante de teste usual, deixando de fora a parte perigosa, -delete
:
find . -mindepth 2 -mtime +5 -print
A parte complicada é que a ação -delete
implica na opção -depth
. O comando incluindo delete é realmente
find . -depth -mindepth 2 -mtime +5 -print -delete
e deve ser testado com
find . -depth -mindepth 2 -mtime +5 -print
Isso está intimamente relacionado com os sintomas que você vê; A opção -depth
está alterando o algoritmo traversal de árvore para a árvore do sistema de arquivos de um < pesquisa avançada em profundidade na pré-encomenda para uma pesquisa em profundidade na primeira ordem .
Antes, cada arquivo ou diretório que era alcançado era imediatamente usado e esquecido. Find estava usando a própria árvore para encontrar o caminho. Agora, find
precisará coletar todos os diretórios que podem conter arquivos ou diretórios ainda a serem encontrados, antes de excluir os arquivos nos diretórios mais profundos primeiro . Para isso, ele precisa fazer o trabalho de planejar e lembrar as próprias etapas de passagem e - esse é o ponto - em uma ordem diferente da que a árvore do sistema de arquivos suporta naturalmente. Então, de fato, ele precisa coletar dados em muitos arquivos antes da primeira etapa do trabalho de saída.
O Find precisa controlar alguns diretórios para visitar mais tarde, o que não é um problema para alguns diretórios.
Mas talvez com muitos diretórios, para vários graus de muitos.
Além disso, problemas de desempenho fora do alcance serão notados nesse tipo de situação; Então, é possível que nem mesmo find
seja lento, mas algo mais.
O impacto no desempenho e na memória depende da sua estrutura de diretórios, etc.
As seções relevantes de man find
:
Veja os "Avisos":
ACTIONS
-delete
Delete files; true if removal succeeded. If the removal failed,
an error message is issued. If -delete fails, find's exit status
will be nonzero (when it eventually exits). Use of -delete auto‐
matically turns on the -depth option.
Warnings: Don't forget that the find command line is evaluated as
an expression, so putting -delete first will make find try to
delete everything below the starting points you specified. When
testing a find command line that you later intend to use with
-delete, you should explicitly specify -depth in order to avoid
later surprises. Because -delete implies -depth, you cannot use‐
fully use -prune and -delete together.
[ ... ]
E, de uma seção adiante:
OPTIONS
[ ... ]
-depth Process each directory's contents before the directory itself.
The -delete action also implies -depth.
A solução mais rápida para excluir os arquivos
Você realmente não precisa excluir os diretórios na mesma execução de excluir os arquivos, certo? Se não estamos excluindo diretórios, não precisamos de todo o -depth
, podemos apenas encontrar um arquivo e excluí-lo, e passar para o próximo, como você propôs.
Desta vez, podemos usar a variante de impressão simples para testar o find
, com -print
implícito.
Queremos encontrar apenas arquivos simples, sem links simbólicos, diretórios, arquivos especiais, etc:
find . -mindepth 2 -mtime +5 -type f
Usamos xargs
para excluir mais de um arquivo por rm
processo iniciado, cuidando de nomes de arquivos ímpares usando um byte nulo como separador:
Testando este comando - observe o echo
na frente do rm
, então ele imprime o que será executado posteriormente:
find . -mindepth 2 -mtime +5 -type f -print0 | xargs -0 echo rm
As linhas serão muito longas e difíceis de ler; Para um teste inicial, pode ajudar a obter resultados legíveis com apenas três arquivos por linha, adicionando -n 3
como os primeiros argumentos de xargs
Se tudo estiver bem, remova o echo
na frente do rm
e execute novamente.
Isso deve ser muito mais rápido ;
No caso de estarmos falando de milhões de arquivos - você escreveu 600 milhões de arquivos no total - há algo mais a ser levado em conta:
A maioria dos programas, incluindo find
, lê diretórios usando a chamada da biblioteca readdir (3)
. Isso geralmente usa um buffer de 32 KB para ler diretórios;
Isso se torna um problema quando os diretórios, contendo listas enormes de nomes de arquivos possivelmente longos, são grandes.
A maneira de contornar isso é usar diretamente a chamada do sistema para ler entradas de diretório,
getdents (2)
, e manipular o buffer de uma forma mais adequada.
Para detalhes, consulte Você pode listar um diretório contendo 8 milhões de arquivos! Mas não com ls ..
(Seria interessante se você pudesse adicionar detalhes à sua pergunta sobre os números típicos de arquivos por diretórios, diretórios por diretório, profundidade máxima de caminhos; Além disso, qual sistema de arquivos é usado.)
(Se ainda estiver lento, você deve verificar os problemas de desempenho do sistema de arquivos.)