재귀 grep 대 find / -type f -exec grep {} \; 어느 쪽이 더 효율적 / 빠른가? 무엇입니까 : 재귀 grep 또는 exec

전체 파일 시스템에서 어떤 파일이 문자열을 포함 하는지를 찾는 데 더 효과적인 것은 무엇입니까 : 재귀 grep 또는 exec 문에서 grep으로 찾기? 파일 확장자 또는 파일 이름과 일치하는 정규 표현식을 알고 있지만 -type f어느 것이 더 나은지 알면 적어도 일부 필터링을 수행 할 수 있기 때문에 찾기가 더 효율적이라고 가정합니다 . GNU grep 2.6.3; 찾기 (GNU findutils) 4.4.2

예:

grep -r -i 'the brown dog' /

find / -type f -exec grep -i 'the brown dog' {} \;



답변

확실하지 않습니다 :

grep -r -i 'the brown dog' /*

정말 당신이 의미하는 것입니다. 이것은 숨겨지지 않은 모든 파일과 디렉토리에서 재귀 적으로 grep을 의미합니다 /(그러나 여전히 숨겨진 파일 내부와 디렉토리 내부를 살펴보십시오).

당신이 의미한다고 가정 :

grep -r -i 'the brown dog' /

몇 가지 참고할 사항 :

  • 모든 grep구현이 지원되는 것은 아닙니다 -r. 디렉토리 트리를 탐색 할 때 일부는 디렉토리에 대한 심볼릭 링크를 따릅니다 (즉, 동일한 파일에서 여러 번 보거나 무한 루프로 실행될 수 있음). 일부는 장치 파일 내부를 /dev/zero보거나 (예를 들어 꽤 오랜 시간이 걸릴 것입니다 ) 파이프 또는 이진 파일 … 일부는 그렇지 않습니다.
  • grep파일을 발견하자마자 파일 내부를 조사 하기 시작하는 것이 효율적 입니다. 그러나 파일을 찾는 동안 더 이상 검색 할 파일을 더 이상 찾지 않습니다 (대부분의 경우와 마찬가지로)

너의:

find / -type f -exec grep -i 'the brown dog' {} \;

파일 당 -r하나를 실행하기 때문에 (여기서 의미가없는 제거 )는 비효율적 grep입니다. ;하나의 인수 만 허용하는 명령에만 사용해야합니다. 또한 여기에서는 grep하나의 파일 만 보이 므로 파일 이름이 인쇄되지 않으므로 일치하는 위치를 알 수 없습니다.

장치 파일, 파이프, 심볼릭 링크를 보지 않고 심볼릭 링크를 따르지 않지만 여전히 잠재적으로 내부를 살펴보고 있습니다 /proc/mem.

find / -type f -exec grep -i 'the brown dog' {} +

grep가능한 적은 명령이 실행 되기 때문에 훨씬 나을 것입니다. 마지막 실행에 파일이 하나만 있지 않으면 파일 이름을 얻게됩니다. 이를 위해서는 다음을 사용하는 것이 좋습니다.

find / -type f -exec grep -i 'the brown dog' /dev/null {} +

또는 GNU grep:

find / -type f -exec grep -Hi 'the brown dog' {} +

참고 grep때까지 시작되지 않습니다는 find이에 씹어 때문에 일부 초기 지연이있을 것이다 충분한 파일을 발견했다. 그리고 find이전 grep으로 돌아올 때까지 더 많은 파일을 계속 검색하지 않습니다 . 큰 파일 목록을 할당하고 전달하면 약간의 영향을 미치므로 grep -rsymlink를 따르거나 장치 내부를 보지 않는 것보다 효율성이 떨어질 수 있습니다.

GNU 도구로 :

find / -type f -print0 | xargs -r0 grep -Hi 'the brown dog'

위와 grep같이 가능한 적은 인스턴스가 실행되지만 find첫 번째 grep호출이 첫 번째 배치 내부를 찾는 동안 더 많은 파일을 계속 찾습니다. 그러나 이점이 될 수도 있고 아닐 수도 있습니다. 예를 들어 회전식 하드 드라이브에 저장된 데이터 findgrep디스크의 다른 위치에 저장된 데이터에 액세스하면 디스크 헤드가 지속적으로 이동하여 디스크 처리량이 느려집니다. 는 RAID 설정에서 (여기서 findgrep다른 디스크에 액세스 할 수 있습니다) 또는 SSD를에, 그 긍정적 인 변화를 만들 수 있습니다.

RAID 설정에서 여러 개의 동시 grep 호출을 실행 하면 상황이 개선 될 수도 있습니다. 여전히 3 개의 디스크가있는 RAID1 스토리지의 GNU 도구

find / -type f -print0 | xargs -r0 -P2 grep -Hi 'the brown dog'

성능이 크게 향상 될 수 있습니다. 그러나 두 grep번째 grep명령 은 첫 번째 명령 을 채우는 데 충분한 파일이 발견 된 후에 만 ​​시작 됩니다. 더 빨리 발생 하도록 -n옵션을 추가 할 수 있으며 호출 xargs당 더 적은 파일을 전달할 수 있습니다 grep.

또한 xargs출력을 터미널 장치 이외의 것으로 리디렉션하는 경우 grepss가 출력을 버퍼링하기 시작 하므로 s의 출력 grep이 잘못 인터리브 될 수 있습니다. 그 문제를 해결하기 위해 stdbuf -oL(GNU 또는 FreeBSD와 같이 사용 가능한 경우) 그것들 을 사용해야 하거나 (여전히 긴 줄에 문제가있을 수 있습니다 (일반적으로 4KiB 이상)) 각각 별도의 파일로 출력을 작성하고 연결해야합니다 결국.

여기서 찾고있는 문자열은 고정되어 있지 않으므로 (regexp가 아님) -F옵션을 사용하면 차이가 발생할 수 있습니다 ( grep구현물이 이미 최적화하는 방법을 알고 있지는 않음 ).

큰 차이를 만들 수있는 또 다른 것은 멀티 바이트 로캘 인 경우 로캘을 C로 고정하는 것입니다.

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi 'the brown dog'

내부보고 피하려면 /proc, /sys…, 사용 -xdev당신이 검색 할 파일 시스템 및 지정

LC_ALL=C find / /home -xdev -type f -exec grep -i 'the brown dog' /dev/null {} +

또는 명시 적으로 제외하려는 경로를 정리하십시오.

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \
  -type f -exec grep -i 'the brown dog' /dev/null {} +

답변

는 IF *에서 grep호출이 당신에게 중요하지 않습니다 그 첫 번째는 하나의 인스턴스 만 아니라보다 효율적으로해야 grep시작되고 포크는 무료로하지 않습니다. 대부분의 경우 더 빠르지 *만 가장자리의 경우 정렬이 반대로 할 수 있습니다.

기타가있을 수 있습니다 findgrep많은 작은 파일을 더 나은 특히 작동 구조. 대량의 파일 항목과 inode를 한 번에 읽으면 회전하는 미디어의 성능이 향상 될 수 있습니다.

그러나 syscall 통계를 살펴 보겠습니다.

검색

> strace -cf find . -type f -exec grep -i -r 'the brown dog' {} \;
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.86    0.883000        3619       244           wait4
  0.53    0.004809           1      9318      4658 open
  0.46    0.004165           1      6875           mmap
  0.28    0.002555           3       977       732 execve
  0.19    0.001677           2       980       735 stat
  0.15    0.001366           1      1966           mprotect
  0.09    0.000837           0      1820           read
  0.09    0.000784           0      5647           close
  0.07    0.000604           0      5215           fstat
  0.06    0.000537           1       493           munmap
  0.05    0.000465           2       244           clone
  0.04    0.000356           1       245       245 access
  0.03    0.000287           2       134           newfstatat
  0.03    0.000235           1       312           openat
  0.02    0.000193           0       743           brk
  0.01    0.000082           0       245           arch_prctl
  0.01    0.000050           0       134           getdents
  0.00    0.000045           0       245           futex
  0.00    0.000041           0       491           rt_sigaction
  0.00    0.000041           0       246           getrlimit
  0.00    0.000040           0       489       244 ioctl
  0.00    0.000038           0       591           fcntl
  0.00    0.000028           0       204       188 lseek
  0.00    0.000024           0       489           set_robust_list
  0.00    0.000013           0       245           rt_sigprocmask
  0.00    0.000012           0       245           set_tid_address
  0.00    0.000000           0         1           uname
  0.00    0.000000           0       245           fchdir
  0.00    0.000000           0         2         1 statfs
------ ----------- ----------- --------- --------- ----------------
100.00    0.902284                 39085      6803 total

grep 만

> strace -cf grep -r -i 'the brown dog' .
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 40.00    0.000304           2       134           getdents
 31.71    0.000241           0       533           read
 18.82    0.000143           0       319         6 openat
  4.08    0.000031           4         8           mprotect
  3.29    0.000025           0       199       193 lseek
  2.11    0.000016           0       401           close
  0.00    0.000000           0        38        19 open
  0.00    0.000000           0         6         3 stat
  0.00    0.000000           0       333           fstat
  0.00    0.000000           0        32           mmap
  0.00    0.000000           0         4           munmap
  0.00    0.000000           0         6           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0       245       244 ioctl
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0       471           fcntl
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           futex
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0       132           newfstatat
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.000760                  2871       466 total

답변

SSD를 사용하고 탐색 시간을 무시할 수 있다면 GNU 병렬을 사용할 수 있습니다.

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 '
    grep -i -r 'the brown dog' {}
'

find찾은 내용에 따라 최대 8 개의 grep 프로세스를 동시에 실행합니다 .

이렇게하면 하드 디스크 드라이브가 작동하지만 SSD가이를 잘 처리해야합니다.


답변

이것에 대해 고려해야 할 또 하나의 사항은 다음과 같습니다.

grep 이 재귀 적으로 수행해야 할 디렉토리에 시스템의 nofile 설정 보다 많은 파일이 포함되어 있습니까? (예 : 열린 파일 핸들 수, 대부분의 Linux 배포판에서 기본값은 1024입니다)

그렇다면 특정 버전의 grep 이 최대 열린 파일 핸들 설정보다 많은 파일을 가진 디렉토리에 도달 할 때 인수 목록에 너무 긴 오류가 발생하기 때문에 find 는 확실히 진행 방법 입니다.

그냥 내 2 Just.