전체 파일 시스템에서 어떤 파일이 문자열을 포함 하는지를 찾는 데 더 효과적인 것은 무엇입니까 : 재귀 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 -r
symlink를 따르거나 장치 내부를 보지 않는 것보다 효율성이 떨어질 수 있습니다.
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가 출력을 버퍼링하기 시작 하므로 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
시작되고 포크는 무료로하지 않습니다. 대부분의 경우 더 빠르지 *
만 가장자리의 경우 정렬이 반대로 할 수 있습니다.
기타가있을 수 있습니다 find
– grep
많은 작은 파일을 더 나은 특히 작동 구조. 대량의 파일 항목과 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.