전체 파일 시스템에서 문자열이 포함 된 파일을 찾는 데 더 효율적인 방법은 무엇입니까? 재귀 적 grep 또는 exec 문에서 grep으로 찾기 파일 확장자 또는 파일 이름과 일치하는 정규식을 알고 있으면 필터링을 수행 할 수 있기 때문에 find가 더 효율적이라고 가정합니다. 그러나 -type f
만 알고있는 경우 더 좋습니다. ? GNU grep 2.6.3; find (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
. 작동 방식이 다릅니다. 일부는 디렉토리 트리를 탐색 할 때 디렉토리에 대한 심볼릭 링크를 따릅니다 (즉, 동일한 파일에서 veral 시간을 사용하거나 무한 루프에서 실행 됨) 일부는 그렇지 않습니다. 일부는 장치 파일 (예 :/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
는 출력 버퍼링을 시작합니다. 이는 해당 grep
의 출력이 아마도 잘못 인터리브 될 수 있음을 의미합니다. (GNU 또는 FreeBSD와 같이 사용 가능한 경우)를 사용하여 문제를 해결하거나 (매우 긴 줄 (일반적으로> 4KiB)에 여전히 문제가있을 수 있음) 또는 각각 별도의 파일에 출력을 작성하고 모두 연결 결국.
여기에서 찾고있는 문자열은 고정 (정규식이 아님)이므로 -F
옵션을 사용하면 차이가 발생할 수 있습니다. grep
구현은 이미이를 최적화하는 방법을 알고 있습니다.
또 다른 큰 차이를 만드는 것은 “멀티 바이트 로케일에있는 경우 로케일을 C로 수정하는 것입니다.
find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi "the brown dog"
, /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 {} +
댓글
- ‘ 누군가가 {} 및 +의 의미를 설명하거나 리소스를 가리킬 수 있다고 생각하지 않습니다. ‘ exec, grep에 대한 man 페이지에서 볼 수 없거나 사용중인 Solaris 상자에서 ‘ 찾을 수 없습니다. 쉘이 파일 이름을 연결하고 grep에 전달하는 것입니까?
- @Poldie, ‘는 Solaris man 페이지
- 아, 네. ‘ 맨 페이지 내에서 검색하는 동안 내 {문자를 이스케이프하지 않았습니다. 귀하의 링크가 더 좋습니다. 매뉴얼 페이지를 읽기가 끔찍합니다.
- RAID1 (디스크 3 개 포함)? 얼마나 이상할까요 …
- @tink, 예 RAID1은 2 개 이상의 디스크에 있습니다. 2 개의 디스크에 비해 3 개의 디스크를 사용하면 중복성과 읽기 성능이 향상되는 반면 쓰기 성능은 거의 동일합니다. 2 개가 아닌 3 개의 디스크를 사용하면 오류를 수정할 수도 있습니다. 복사본 중 하나에서 비트가 뒤집힐 때 ‘ 모두 확인하여 어느 것이 올바른지 알 수 있습니다. 2 개의 디스크를 사용하는 동안 3 개의 사본이 있지만 ‘ 정말 알 수 없습니다.
답변
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
댓글
- 전체 파일 시스템을 검색하는 규모에서 포크는 무시할 수 있습니다. I / O를 줄이고 자합니다.
- OP의 오류이지만 비교가 잘못되었으므로
-r
플래그를 제거해야합니다.find
를 사용하는 경우 div id = “2b5be2b501”>
. 발생한open
의 수를 비교하여 동일한 파일을 반복해서 검색했음을 알 수 있습니다.
-r
는 -type f
인수가 디렉토리임을 보장하지 않기 때문에 무해해야합니다. 여러 open()
는 각 호출 (라이브러리, 현지화 데이터 …)에서 grep
에 의해 열린 다른 파일로 내려갈 가능성이 높습니다. 내 답변 btw를 수정 해 주셔서 감사합니다) 답변
SSD를 사용하고 시간을 찾는 경우 무시해도됩니다. GNU 병렬을 사용할 수 있습니다.
find /path -type f | parallel --gnu --workdir "$PWD" -j 8 " grep -i -r "the brown dog" {} "
이는 찾았습니다.
이렇게하면 하드 디스크 드라이브가 손상되지만 SSD는이를 잘 처리합니다.
답변
이 문제에 대해 고려해야 할 한 가지 더는 다음과 같습니다.
grep 이 재귀 적으로 이동해야하는 모든 디렉토리에 시스템의 nofile 설정보다 파일이 있습니까? (예 : 열린 파일 핸들 수, 대부분의 Linux 배포판에서 기본값은 1024입니다.)
그렇다면 grep 특정 버전 이후로 찾기 가 확실히 갈 방법입니다. / em>은 최대 열린 파일보다 많은 파일이있는 디렉토리에 도달하면 인수 목록이 너무 김 오류와 함께 폭발합니다. 설정을 처리합니다.
단지 내 2 ¢.
댓글
- 왜
grep
폭파? 뒤에/
가있는 경로를 제공하고-R
it ‘ 디렉토리를 간단히 반복합니다. 쉘 은 ‘ 쉘 글로브를 제공하지 않는 한 아무것도 확장하지 않습니다. 따라서 주어진 예 (/*
)에서/
의 내용 만 중요하며, 셸에서 인수로 전달되지 않았습니다.
- 음, OP가 재귀 검색에 대해 묻는 것을 고려하면 (예 : ” grep -r -i ‘ 갈색 개 ‘ / * “), 본 적이 있습니다. GNU ‘의 grep (최소 버전 2.9) : ” -bash : / bin / grep : 인수 목록이 너무 깁니다 ” 하위 디렉토리가 140,000 개가 넘는 디렉토리에서 사용 된 OP를 정확히 검색합니다.
-exec {} +
양식은 더 적은 포크를 수행하므로-exec {} \;
보다 빠릅니다. 정확하게 얻으려면-H
(또는-h
)를grep
옵션에 추가해야 할 수 있습니다. 동등한 출력.grep