`find 왜? -f 유형은`find '보다 오래 걸립니까?


15

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);
    }
}

2
find디렉토리의 내용을 재귀 적으로 걸기 위해 주어진 경로가 파일이나 디렉토리에 해당하는지 확인 해야하는 것처럼 보입니다 . -디렉토리인지 확인해야하며 파일인지 여부를 확인할 필요가 없습니다. 명명 된 파이프, 심볼릭 링크, 블록 특수 장치, 소켓 등의 다른 항목 유형이 있습니다. 따라서 디렉토리인지 확인하기 위해 이미 검사를 수행 했음에도 불구하고 이것이 일반 파일인지 아는 것은 아닙니다.
RealSkeptic

busybox find는 4,3k dirs 및 2,8k 파일을 가진 임의의 디렉토리에 적용되며 2,8k 파일은 해당 디렉토리와 관계 -type f없이 동시에 실행 됩니다. 그러나 처음에 리눅스 커널은 그것을 캐시에로드했고 처음 발견은 느렸다.

1
내 첫번째 추측이이었다 -type f옵션을 야기 find전화 stat()또는 fstat()파일 이름이 파일에 해당 여부를 확인하기 위해 또는 어떤 순서로, 등 등 내가했던 디렉토리, 심볼릭 링크 straceA의 find . find . -type f및 추적이 거의 동일했다, write()디렉토리 이름이 있는 호출 에서만 다릅니다 . 그래서 나는 모른다. 그러나 나는 대답을 알고 싶다.
Bruce Ediger

1
실제로 질문에 대한 대답은 아니지만 time명령 실행 시간을 확인하는 기본 제공 명령이 있으므로 테스트를 위해 사용자 지정 스크립트를 작성할 필요가 없습니다.
Elronnd

답변:


16

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

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

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


이것은 여전히 ​​관련이 있습니까? find소스를 보면 요즘에는 단순히 fts_open()and 를 사용합니다 fts_read().
RealSkeptic

@RealSkeptic 최근 버전에서 변경 되었습니까? 소스를 확인하지는 않았지만 실험적으로 데비안 스 테이블의 버전 4.4.2는 stat디렉토리 링크 수로 인해 필요하지 않을 때 호출을 최적화 하며 -noleaf옵션은 설명서에 설명되어 있습니다.
Gilles 'SO- 악마 중지'

버전 stat에서도 최적화됩니다 fts.... 해당 플래그를 해당 플래그를 fts_open호출에 전달합니다 . 그러나 확실하지 않은 것은 여전히 ​​링크 수를 확인하는 것입니다. 대신 반환 된 fts 레코드에 "directory"플래그 중 하나가 있는지 확인합니다. 그 fts_read자체가 해당 플래그를 설정하기 위해 링크를 확인하지만 find그렇지 않은 것일 수 있습니다 . fts을 호출 하여 버전이 의존하는지 확인할 수 있습니다 find --version.
RealSkeptic

@Gilles, find이론적으로 디렉토리의 모든 항목이 모두 디렉토리인지 결정하고 해당 정보를 사용할 수 있습니까?
Gregory Nisbet

@GregoryNisbet 이론적으로는 그렇습니다.하지만 소스 코드 (지금 확인했습니다)는 그렇게하지 않습니다. 아마도 매우 드문 경우이기 때문입니다.
Gilles 'SO- 악마 중지
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.