`find 왜? -f 유형은`find ‘보다 오래 걸립니까? 필터를 사용하는 가장 직접적인

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

나는 (이러한 두 명령의 성능을 테스트하는 몇 가지 코드를 작성 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.

우분투 15.10에서

벤치마킹에 사용한 펄 스크립트는 다음과 같습니다.

#!/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);
    }
}


답변

GNU의 발견은 적용 할 수있는 최적화가 find .아니라에을 find . -type f: 그것은 디렉토리에 남아있는 항목 중 하나에 해당하지 모르는 경우 디렉토리는, 다음합니다 (로 파일 형식을 결정하기 위해 귀찮게하지 않습니다 stat중 하나하지 않는 시스템 호출) 검색 기준이 필요합니다. stat정보는 일반적으로 포함 디렉토리가 아닌 디스크의 별도 위치에있는 inode에 있기 때문에 호출하는 데 상당한 시간이 걸릴 수 있습니다.

어떻게 알 수 있습니까? 디렉토리의 링크 수는 디렉토리의 수를 나타냅니다. 일반적인 Unix 파일 시스템에서 디렉토리의 링크 수는 2에 디렉토리 수를 더한 것입니다. 하나는 상위 디렉토리 .항목, 하나는 ..하위 디렉토리 항목입니다.

-noleaf옵션은 find이 최적화를 적용하지 않도록 지시 합니다. find디렉토리 링크 수가 Unix 규칙을 따르지 않는 일부 파일 시스템에서 호출 된 경우에 유용합니다 .