Sembra find
dovrebbe comunque verificare se un determinato percorso corrisponde a un file o una directory per poter percorrere ricorsivamente il contenuto delle directory.
Ecco alcune motivazioni e cosa ho fatto a livello locale per convincermi che find . -type f
è davvero più lento di find .
. Non ho ancora scavato nel codice sorgente di GNU find.
Quindi sto eseguendo il backup di alcuni dei file nel mio $HOME/Workspace
directory ed escludendo i file che sono dipendenze dei miei progetti o file di controllo della versione.
Quindi ho eseguito il seguente comando che è stato eseguito rapidamente
% find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-and-dirs.txt
find
reindirizzato a grep
potrebbe essere una cattiva forma, ma sembrava il modo più diretto per utilizzare un filtro regex negato.
Il comando seguente include solo i file nell'output di trova e ha richiesto molto più tempo.
% find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-only.txt
Ho scritto del codice per testare le prestazioni di questi due comandi (con dash
e tcsh
, giusto per escludere eventuali effetti che la shell potrebbe avere, anche se non dovrebbero essercene). Il tcsh
i risultati sono stati omessi perché sono essenzialmente gli stessi.
I risultati che ho ottenuto hanno mostrato una penalizzazione delle prestazioni del 10% per -type f
Ecco l'output del programma che mostra il tempo impiegato per eseguire 1000 iterazioni di vari comandi.
% 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
Testato con
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Su Ubuntu 15.10
Ecco lo script perl che ho usato per il 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 "%snn", time_command(@$shell, $command);
}
}
Risposta accettata:
GNU find ha un'ottimizzazione che può essere applicata a find .
ma non per find . -type f
:se sa che nessuna delle voci rimanenti in una directory sono directory, allora non si preoccupa di determinare il tipo di file (con il stat
chiamata di sistema) a meno che uno dei criteri di ricerca non lo richieda. Chiamando stat
può richiedere un tempo misurabile poiché le informazioni si trovano in genere nell'inode, in una posizione separata sul disco, piuttosto che nella directory che le contiene.
Come fa a saperlo? Perché il conteggio dei collegamenti su una directory indica quante sottodirectory ha. Sui tipici filesystem Unix, il conteggio dei collegamenti di una directory è 2 più il numero di directory:una per la voce della directory nel suo genitore, una per il .
voce e uno per il ..
voce in ogni sottodirectory.
Il -noleaf
l'opzione dice find
di non applicare questa ottimizzazione. Questo è utile se find
viene invocato su alcuni filesystem in cui i conteggi dei collegamenti alle directory non seguono la convenzione Unix.