전체 파일 시스템에서 문자열이 포함된 파일을 찾는 데 재귀 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
액세스하면 디스크 헤드가 지속적으로 이동하여 디스크 처리량이 감소합니다. 이는 grep
RAID 설정( 다른 디스크에 액세스 find
할 수 있음 grep
) 또는 SSD에 긍정적인 영향을 미칠 수 있습니다.
RAID 설정에서 다중 실행동시에 grep
전화를 하면 상황이 개선될 수도 있습니다. 여전히 3개의 디스크 RAID1 스토리지에서 GNU 도구를 사용하고 있습니다.
find / -type f -print0 | xargs -r0 -P2 grep -Hi 'the brown dog'
성능이 크게 향상될 수 있습니다. 그러나 grep
첫 번째 명령을 채울 만큼 충분한 파일이 발견될 때까지 grep
두 번째 명령은 시작되지 않습니다 . 이 작업이 더 빠르게 수행되도록(그리고 호출당 더 적은 수의 파일을 전달하도록) -n
옵션 을 추가할 수 있습니다 .xargs
grep
xargs
또한 출력을 터미널 장치가 아닌 다른 것으로 리디렉션 하는 경우 greps
s는 출력 버퍼링을 시작합니다. 이는 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¢.