find
ディレクトリの内容を再帰的にたどるには、とにかく、指定されたパスがファイルまたはディレクトリに対応するかどうかを確認する必要があるようです。
ここにいくつかの動機と、find . -type f
実際にが遅いことを自分に納得させるためにローカルで行ったことがありますfind .
。GNU findのソースコードをまだ掘り下げていません。
そのため、$HOME/Workspace
ディレクトリ内のいくつかのファイルをバックアップし、プロジェクトの依存関係またはバージョン管理ファイルのいずれかであるファイルを除外しています。
だから私はすぐに実行される次のコマンドを実行しました
% find Workspace/ | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-and-dirs.txt
find
パイプ処理は不適切grep
な形式かもしれませんが、否定正規表現フィルターを使用する最も直接的な方法のように思えました。
次のコマンドでは、findの出力にファイルのみが含まれ、著しく時間がかかりました。
% find Workspace/ -type f | grep -v '/vendor\|/node_modules/\|Workspace/sources/\|/venv/\|/.git/' > ws-files-only.txt
これらの2つのコマンドのパフォーマンスをテストするためのコードをいくつか作成しました(と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
のfind .
とfind . -type f
、トレースはほぼ同一でしたwrite()
ディレクトリ名が含まれる呼び出しのみが異なります。だから、私は知りませんが、答えを知りたいです。
time
コマンドの実行にかかる時間を確認するための組み込みコマンドがあります。テストするためにカスタムスクリプトを記述する必要はありません。
find
ディレクトリの内容を再帰的にたどるには、とにかく特定のパスがファイルまたはディレクトリに対応しているかどうかをチェックする必要があるようです。-ディレクトリかどうかを確認する必要があります。ファイルかどうかを確認する必要はありません。他のエントリタイプがあります:名前付きパイプ、シンボリックリンク、ブロック特殊デバイス、ソケット...ですから、ディレクトリであるかどうかを確認するために既にチェックを行っているかもしれませんが、それが通常のファイルであるかどうかを知っているわけではありません。