Il semble que find
devrait de toute façon vérifier si un chemin donné correspond à un fichier ou à un répertoire afin de parcourir récursivement le contenu des répertoires.
Voici quelques motivations et ce que j'ai fait localement pour me convaincre que find . -type f
est vraiment plus lent que find .
. Je n'ai pas encore creusé dans le code source de recherche GNU.
Je sauvegarde donc certains des fichiers dans mon $HOME/Workspace
répertoire, et en excluant les fichiers qui sont soit des dépendances de mes projets, soit des fichiers de contrôle de version.
J'ai donc exécuté la commande suivante qui s'est exécutée rapidement
% find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-and-dirs.txt
find
redirigé vers grep
peut-être une mauvaise forme, mais cela semblait être le moyen le plus direct d'utiliser un filtre regex inversé.
La commande suivante inclut uniquement les fichiers dans la sortie de find et a pris sensiblement plus de temps.
% find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-only.txt
J'ai écrit du code pour tester les performances de ces deux commandes (avec dash
et tcsh
, juste pour exclure tout effet que le shell pourrait avoir, même s'il ne devrait pas y en avoir). Le tcsh
les résultats ont été omis car ils sont essentiellement les mêmes.
Les résultats que j'ai obtenus ont montré une pénalité de performance d'environ 10 % pour -type f
Voici la sortie du programme montrant le temps nécessaire pour exécuter 1000 itérations de diverses commandes.
% 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
Testé avec
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Sur Ubuntu 15.10
Voici le script perl que j'ai utilisé pour l'analyse comparative
#!/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);
}
}
Réponse acceptée :
GNU find a une optimisation qui peut être appliquée à find .
mais pas pour find . -type f
:s'il sait qu'aucune des entrées restantes dans un répertoire n'est un répertoire, alors il ne prend pas la peine de déterminer le type de fichier (avec le stat
appel système) sauf si l'un des critères de recherche l'exige. Appel de stat
peut prendre un temps mesurable car les informations se trouvent généralement dans l'inode, dans un emplacement séparé sur le disque, plutôt que dans le répertoire contenant.
Comment sait-il ? Parce que le nombre de liens sur un répertoire indique le nombre de sous-répertoires dont il dispose. Sur les systèmes de fichiers Unix typiques, le nombre de liens d'un répertoire est de 2 plus le nombre de répertoires :un pour l'entrée du répertoire dans son parent, un pour le .
entrée, et une pour le ..
entrée dans chaque sous-répertoire.
Le -noleaf
l'option indique find
de ne pas appliquer cette optimisation. Ceci est utile si find
est invoqué sur certains systèmes de fichiers où le nombre de liens de répertoire ne suit pas la convention Unix.