Схоже find
, доведеться перевірити, чи відповідає той чи інший шлях файлу чи директорії, щоб рекурсивно проходити вміст каталогів.
Ось певна мотивація і те, що я зробив на місцевому рівні, щоб переконати себе, що find . -type f
насправді це повільніше, ніж find .
. Я ще не вкопався у вихідному коді пошуку GNU.
Тому я створюю резервну копію деяких файлів у моєму $HOME/Workspace
каталозі та виключаю файли, які є або залежностями моїх проектів, або файлами контролю версій.
Тому я запустив таку команду, яка швидко виконується
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
find
конвеєру grep
може бути поганою формою, але це здавалося самим безпосереднім чином , щоб використовувати заперечення регулярного виразу фільтра.
Наступна команда включає лише файли у висновку пошуку та зайняла помітно довше.
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
Я написав якийсь код, щоб перевірити працездатність цих двох команд (з dash
і tcsh
, просто щоб виключити будь-які ефекти, які може мати оболонка, хоча їх не повинно бути). Ці tcsh
результати були опущені , оскільки вони по суті те ж саме.
Результати, які я отримав, показали 10-відсотковий штраф за ефективність -type f
Ось результат програми, який показує кількість часу, необхідного для виконання 1000 ітерацій різних команд.
% 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
Тестували с
% find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
У Ubuntu 15.10
Ось сценарій perl, який я використав для тестування
#!/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
і без нього. Але спочатку ядро Linux завантажило його в кеш, і найперше пошук виявився повільніше.
-type f
опція викликала find
дзвінок stat()
або що- fstat()
небудь для того, щоб дізнатись, чи відповідає ім'я файлу файлу, директорії, симпосилання тощо. Я зробив записи strace
a find .
і a, find . -type f
і слід був майже однаковий, відрізняються лише write()
дзвінками, які мали в них імена каталогів. Отже, я не знаю, але хочу знати відповідь.
time
вбудована команда, щоб побачити, скільки часу потрібно виконувати команді, вам не потрібно було писати спеціальний сценарій для тестування.
find
, доведеться перевірити, чи відповідає той чи інший шлях файлу чи директорії, щоб рекурсивно проходити вміст каталогів. - доведеться перевірити, чи це каталог, не доведеться перевіряти, чи це файл. Є й інші типи запису: іменовані труби, символічні посилання, блокування спеціальних пристроїв, розетки ... Тож, хоча, можливо, це було зроблено перевірки, щоб побачити, чи це каталог, це не означає, що він знає, чи це звичайний файл.