`find.-type f`が`find.`より長くかかるのはなぜですか?

`find.-type f`が`find.`より長くかかるのはなぜですか?

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

私はこれらの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);
    }
}

ベストアンサー1

find .GNU findには適用できますが適用できない最適化があります。ディレクトリの残りの項目のどれもディレクトリではないことがわかっている場合は、検索の1つでない限りfind . -type f(システムコールを使用して)ファイルの種類を決定しません。stat条件が必要です。stat情報は通常、含まれているディレクトリではなくディスク上の別の場所にあるinodeにあるため、呼び出しにはかなり長い時間がかかることがあります。

どうすればわかりますか?ディレクトリ内のリンクの数は、そのディレクトリ内のサブディレクトリの数を表すためです。一般的な Unix ファイルシステムでは、ディレクトリのリンク数は 2 にディレクトリ数を加えた値です。親ディレクトリのディレクトリエントリは1、各サブディレクトリのエントリは1、各サブディレクトリのエントリは.1です。..

この-noleafオプションは、findこの最適化が適用されないことを示します。これはfind、ディレクトリリンク計算がUnixルールに従わない特定のファイルシステムで呼び出される場合に便利です。

おすすめ記事