Parece que find
teria que verificar se um determinado caminho corresponde a um arquivo ou diretório de qualquer maneira para percorrer recursivamente o conteúdo dos diretórios.
Aqui estão algumas motivações e o que eu fiz localmente para me convencer de que find . -type f
é realmente mais lento que find .
. Eu ainda não pesquisei o código fonte do GNU find.
Por isso, estou fazendo backup de alguns arquivos no diretório $HOME/Workspace
e excluindo arquivos que são dependências de meus projetos ou arquivos de controle de versão.
Então eu corri o seguinte comando que executou rapidamente
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
find
canalizado para grep
pode estar em má forma, mas parecia ser a maneira mais direta de usar um filtro regex negado.
O seguinte comando inclui apenas arquivos na saída do find e demorou muito mais tempo.
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
Eu escrevi algum código para testar o desempenho desses dois comandos (com dash
e tcsh
, apenas para excluir quaisquer efeitos que o shell possa ter, mesmo que não haja nenhum). Os resultados tcsh
foram omitidos porque são essencialmente os mesmos.
Os resultados que obtive mostraram uma penalidade de desempenho de 10% por -type f
Aqui está a saída do programa que mostra o tempo gasto para executar 1000 iterações de vários comandos.
% perl tester.pl
/bin/sh -c find Workspace/ >/dev/null
82.986582
/bin/sh -c find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
90.313318
/bin/sh -c find Workspace/ -type f >/dev/null
102.882118
/bin/sh -c find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
109.872865
Testado com
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
No Ubuntu 15.10
Aqui está o script perl que eu usei para benchmarking
#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw[gettimeofday tv_interval];
my $max_iterations = 1000;
my $find_everything_no_grep = <<'EOF';
find Workspace/ >/dev/null
EOF
my $find_everything = <<'EOF';
find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
EOF
my $find_just_file_no_grep = <<'EOF';
find Workspace/ -type f >/dev/null
EOF
my $find_just_file = <<'EOF';
find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > /dev/null
EOF
my @finds = ($find_everything_no_grep, $find_everything,
$find_just_file_no_grep, $find_just_file);
sub time_command {
my @args = @_;
my $start = [gettimeofday()];
for my $x (1 .. $max_iterations) {
system(@args);
}
return tv_interval($start);
}
for my $shell (["/bin/sh", '-c']) {
for my $command (@finds) {
print "@$shell $command";
printf "%s\n\n", time_command(@$shell, $command);
}
}