Wygląda na to, find
że musiałbym sprawdzić, czy dana ścieżka i tak odpowiada plikowi lub katalogowi, aby rekursywnie przechodzić przez zawartość katalogów.
Oto motywacja i to, co zrobiłem lokalnie, aby przekonać siebie, że find . -type f
naprawdę jest wolniejsze niż find .
. Nie zagłębiłem się jeszcze w kod źródłowy GNU find.
Tworzę więc kopie zapasowe niektórych plików w moim $HOME/Workspace
katalogu i wykluczam pliki, które są albo zależnościami moich projektów, albo plikami kontroli wersji.
Uruchomiłem więc następujące polecenie, które wykonałem szybko
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
find
przesyłane strumieniowo do grep
może być złej postaci, ale wydawało się, że jest to najbardziej bezpośredni sposób na użycie zanegowanego filtra regex.
Następujące polecenie zawiera tylko pliki w wyjściu find i zajęło zauważalnie więcej czasu.
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
Napisałem trochę kodu, aby przetestować działanie tych dwóch poleceń (z dash
i tcsh
, aby wykluczyć jakiekolwiek efekty, jakie może mieć powłoka, nawet jeśli nie powinno być żadnych). Te tcsh
wyniki zostały pominięte, ponieważ są w zasadzie takie same.
Wyniki, które uzyskałem, pokazały około 10% kary za wydajność -type f
Oto wynik programu pokazujący czas potrzebny do wykonania 1000 iteracji różnych poleceń.
% 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
Testowane z
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
Na Ubuntu 15.10
Oto skrypt perla, którego użyłem do testów porównawczych
#!/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);
}
}
-type f
i bez niego. Ale po raz pierwszy jądro Linuksa załadowało go do pamięci podręcznej i pierwsze wyszukiwanie było wolniejsze.
-type f
opcja spowodowała find
wywołanie stat()
lub fstat()
cokolwiek innego, aby dowiedzieć się, czy nazwa pliku odpowiada plikowi, katalogowi, dowiązaniu symbolicznemu itp. Zrobiłem strace
na A find .
i A, find . -type f
a ślad był prawie identyczny, różni się tylko write()
połączeniami, które zawierają nazwy katalogów. Nie wiem, ale chcę znać odpowiedź.
time
wbudowane polecenie, aby zobaczyć, jak długo trwa wykonanie polecenia, tak naprawdę nie trzeba pisać niestandardowego skryptu, aby przetestować.
find
że musiałbym sprawdzić, czy dana ścieżka i tak odpowiada plikowi lub katalogowi, aby rekursywnie przechodzić przez zawartość katalogów. - musiałby sprawdzić, czy jest to katalog, nie musiałby sprawdzić, czy jest to plik. Istnieją inne typy wpisów: nazwane potoki, dowiązania symboliczne, blokuj urządzenia specjalne, gniazda ... Więc chociaż mógł już sprawdzić, czy jest to katalog, nie znaczy to, że wie, czy jest to zwykły plik.