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 규칙을 따르지 않는 일부 파일 시스템에서 호출 된 경우에 유용합니다 .