재귀 grep과 find / -type f -exec grep {} \; 중 어느 것이 더 효율적이고 빠르나요?

재귀 grep과 find / -type f -exec grep {} \; 중 어느 것이 더 효율적이고 빠르나요?

전체 파일 시스템에서 문자열이 포함된 파일을 찾는 데 재귀 grep과 grep을 사용하여 exec 문 내에서 찾는 것 중 어느 것이 더 효율적입니까? 파일 확장자나 파일 이름과 일치하는 정규식을 알고 있으면 최소한 필터링을 수행할 수 있지만 -type f어느 것이 더 나은지 알 수 있기 때문에 find가 더 효율적일 것이라고 생각합니다. 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' {} \;

답변1

나는 전혀 모른다:

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 -r심볼릭 링크를 따르지 않거나 장치 내부의 파일을 보지 않는 것보다 효율성이 떨어질 수 있습니다.

GNU 도구 사용:

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

위에서 언급한 대로 가능한 한 적은 수의 인스턴스가 실행되지만 grep첫 번째 배치 내에서 조회를 처음 호출할 때 find더 많은 파일이 계속해서 발견됩니다 . grep하지만 이것이 장점일 수도 있고 아닐 수도 있습니다. 예를 들어 데이터가 회전하는 하드 드라이브에 저장되어 있는 경우 디스크의 다른 위치에 저장된 데이터에 find액세스하면 디스크 헤드가 지속적으로 이동하여 디스크 처리량이 감소합니다. 이는 grepRAID 설정( 다른 디스크에 액세스 find할 수 있음 grep) 또는 SSD에 긍정적인 영향을 미칠 수 있습니다.

RAID 설정에서 다중 실행동시에 grep전화를 하면 상황이 개선될 수도 있습니다. 여전히 3개의 디스크 RAID1 스토리지에서 GNU 도구를 사용하고 있습니다.

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

성능이 크게 향상될 수 있습니다. 그러나 grep첫 번째 명령을 채울 만큼 충분한 파일이 발견될 때까지 grep두 번째 명령은 시작되지 않습니다 . 이 작업이 더 빠르게 수행되도록(그리고 호출당 더 적은 수의 파일을 전달하도록) -n옵션 을 추가할 수 있습니다 .xargsgrep

xargs또한 출력을 터미널 장치가 아닌 다른 것으로 리디렉션 하는 경우 grepss는 출력 버퍼링을 시작합니다. 이는 grep해당 s의 출력이 잘못 인터리브될 수 있음을 의미합니다. (GNU 또는 FreeBSD에서 사용 가능한 경우)(아주 긴 줄(보통 4KiB 이상)로 인해 여전히 문제가 있을 수 있음)을 사용하여 이 문제를 해결 하거나 stdbuf -oL각 출력을 별도의 파일에 기록하고 마지막으로 모두 연결해야 합니다.

여기에서 찾고 있는 문자열은 고정되어 있으므로(정규식이 아님) 해당 -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 {} +

답변2

*호출이 중요하지 않은 경우 인스턴스가 하나만 시작되고 포크가 무료가 아니기 grep때문에 첫 번째 호출이 더 효율적입니다 . grep대부분의 경우 사용하면 속도가 더 빨라지지만, *극단적인 경우 정렬을 사용하면 상황이 반전될 수 있습니다.

특히 작은 파일이 많은 경우 더 잘 작동하는 다른 find구조가 있을 수 있습니다 . grep한 번에 많은 수의 파일 항목과 inode를 읽으면 회전 미디어의 성능이 향상될 수 있습니다.

하지만 시스템 호출 통계를 살펴보겠습니다.

찾다

> 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

답변3

SSD를 사용 중이고 검색 시간이 무시할 정도라면 GNU 병렬 처리를 사용할 수 있습니다.

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

이는 발견된 내용에 따라 최대 8개의 grep 프로세스를 동시에 실행합니다 find.

이는 하드 드라이브에 심각한 영향을 주지만 SSD는 이를 잘 처리해야 합니다.

답변4

이에 대해 한 가지 더 고려해야 할 사항은 다음과 같습니다.

모든 디렉토리grep시스템 이상의 내용을 포함하는 파일을 재귀적으로 탐색해야 합니다.파일 없음환경? (예를 들어 열린 파일 핸들 수, 대부분의 Linux 배포판의 기본값은 1024입니다.)

그렇다면,찾다일부 버전 때문에 확실히 갈 길입니다.grep포격을 당할 것이다매개변수 목록이 너무 깁니다.최대 열린 파일 처리 설정보다 많은 파일이 있는 디렉터리에 도달하면 오류가 발생합니다.

그냥 내 2¢.

관련 정보