Es scheint wie find
müsste prüfen, ob ein gegebener Pfad ohnehin einer Datei oder einem Verzeichnis entspricht, um den Inhalt von Verzeichnissen rekursiv zu durchlaufen.
Hier ist etwas Motivation und was ich vor Ort getan habe, um mich davon zu überzeugen, dass find . -type f
ist wirklich langsamer als find .
. Ich habe mich noch nicht mit dem Quellcode von GNU find beschäftigt.
Also sichere ich einige der Dateien in meinem $HOME/Workspace
Verzeichnis und schließt Dateien aus, die entweder Abhängigkeiten meiner Projekte oder Versionskontrolldateien sind.
Also habe ich den folgenden Befehl ausgeführt, der schnell ausgeführt wurde
% find Workspace/ | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-and-dirs.txt
find
an grep
geleitet mag ein schlechter Stil sein, aber es schien der direkteste Weg zu sein, einen negierten Regex-Filter zu verwenden.
Der folgende Befehl bezieht nur Dateien in die Ausgabe von find ein und dauert deutlich länger.
% find Workspace/ -type f | grep -v '/vendor|/node_modules/|Workspace/sources/|/venv/|/.git/' > ws-files-only.txt
Ich habe Code geschrieben, um die Leistung dieser beiden Befehle zu testen (mit dash
und tcsh
, nur um mögliche Auswirkungen der Shell auszuschließen, obwohl es keine geben sollte). Der tcsh
Ergebnisse wurden weggelassen, da sie im Wesentlichen gleich sind.
Die Ergebnisse, die ich erhalten habe, zeigten eine Leistungseinbuße von etwa 10 % für -type f
Hier ist die Ausgabe des Programms, die zeigt, wie viel Zeit benötigt wird, um 1000 Iterationen verschiedener Befehle auszuführen.
% 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
Getestet mit
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Unter Ubuntu 15.10
Hier ist das Perl-Skript, das ich für das Benchmarking verwendet habe
#!/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);
}
}
Akzeptierte Antwort:
GNU find hat eine Optimierung, die auf find .
angewendet werden kann aber nicht find . -type f
:Wenn es weiß, dass keiner der verbleibenden Einträge in einem Verzeichnis Verzeichnisse sind, dann macht es sich nicht die Mühe, den Dateityp zu bestimmen (mit dem stat
Systemaufruf), es sei denn, eines der Suchkriterien erfordert dies. Aufruf von stat
kann messbar viel Zeit in Anspruch nehmen, da sich die Informationen normalerweise im Inode an einem separaten Ort auf der Festplatte und nicht im enthaltenden Verzeichnis befinden.
Woher weiß es? Denn die Linkanzahl eines Verzeichnisses gibt an, wie viele Unterverzeichnisse es hat. Auf typischen Unix-Dateisystemen beträgt die Anzahl der Verknüpfungen eines Verzeichnisses 2 plus die Anzahl der Verzeichnisse:eine für den Eintrag des Verzeichnisses in seinem übergeordneten Verzeichnis, eine für den .
-Eintrag und eine für ..
Eintrag in jedem Unterverzeichnis.
Das -noleaf
Option sagt find
diese Optimierung nicht anzuwenden. Dies ist nützlich, wenn find
wird in einigen Dateisystemen aufgerufen, in denen die Anzahl der Verzeichnislinks nicht der Unix-Konvention entspricht.