비교적 복잡한 기준을 충족하는 파일을 찾아야 합니다. 예를 들어 다음 기준을 모두 충족하는 모든 파일을 찾고 싶습니다.
- AAAA라는 단어가 포함되어 있습니다.
- BBB 또는 CCCCC(둘 다 가능)라는 단어가 포함되어 있습니다.
- DDD라는 단어가 포함되어 있지 않습니다.
단어는 순서에 상관없이 다른 줄(또는 같은 줄)에 나타날 수 있습니다.
find
결합된 솔루션 이 있지만 egrep
명확하지 않습니다.
find . \( -type f -and -exec egrep -q 'BBB|CCCCC' {} \; \
-and -exec egrep -q AAAA {} \; \
-and -not -exec egrep -q DDD {} \; \) -print
이 문제를 해결하는 더 좋은 방법이 있습니까?
답변1
귀하의 솔루션이 작업에 매우 명확한 것 같습니다. 그러나 각 파일에 대해 3개의 프로세스를 생성하므로 속도가 느립니다. 내 생각에는 Awk가 여기에 더 적합하다고 생각합니다. 왜냐하면 ARG_MAX가 허용하는 것처럼 전체 파일 배치를 한 번에 읽을 수 있기 때문 {} +
입니다 {} \;
.
GNU awk:
find . -type f -exec gawk '
BEGINFILE{c1=c2=c3=0}
/AAA/ {c1=1}
/BBB/||/CCC/{c2=1}
/DDD/ {c3=1; nextfile}
ENDFILE{if(c1 && c2 && !c3)print FILENAME}
' {} +
POSIX * :
find . -type f -exec awk '
FNR==1{
if(NR>1 && c1 && c2 && !c3)print f
c1=c2=c3=0
f=FILENAME
}
/AAA/ {c1=1}
/BBB/||/CCC/{c2=1}
/DDD/ {c3=1; nextfile}
END{if(c1 && c2 && !c3)print f}
' {} +
*사실 nextfile
아직 POSIX는 아니지만다음 표준에 의해 승인되었습니다.. POSIX Issue 7 규정 준수를 위해 이를 제거할 수 있습니다. 결과는 동일하지만 성능에 영향을 미칩니다.
노트: awk에 파일을 읽을 수 있는 권한이 없으면 종료됩니다. GNU Find에서 이 -readable
플래그를 추가하면 이를 방지할 수 있습니다. GNU Find를 사용할 수 없는 경우 Test를 추가 필터로 사용할 수 있습니다.
find . -type f -exec test -r {} \; -exec awk '
...
' {} +
그러나 각 파일에 대한 테스트를 생성하면 성능이 저하됩니다.
추가 자료:
답변2
또 다른 접근 방식이 있습니다. 먼저 각 단어를 포함하는 파일 목록을 생성하여 작동합니다.
find . -type f -exec grep -lF 'AAA' {} + > files_with_AAA
find . -type f -exec grep -lF 'BBB' {} + > files_with_BBB
...
그런 다음 목록을 처리하여 조건을 구현할 수 있습니다.
grep -xFf files_with_BBB files_with_AAA # AAA & BBB
grep -xFvf files_with_BBB files_with_AAA # AAA & ~BBB
sort -u files_with_AAA files_with_BBB # AAA | BBB
평가할 파일 수가 많고 표현식이 여러 개인 경우 각 파일을 다시 검사할 필요가 없으므로 속도가 더 빨라집니다.
답변3
특히 이러한 솔루션과의 시간 비교를 보고 싶습니다.립그렙, 병렬 처리 기능이 내장되어 있습니다.
그리고
GNU grep
grep -rLZ 'DDD' | xargs -0 grep -lZ 'AAAA' | xargs -0 grep -lE 'BBB|CCCCC' # if your search terms are literal strings grep -rLZF 'DDD' | xargs -0 grep -lZF 'AAAA' | xargs -0 grep -lF -e 'BBB' -e 'CCCCC'
그리고
rg
. 재귀 검색은 기본적으로 활성화되어 있으며 일부 파일도 기본적으로 무시됩니다. 해당 파일이 결과에 영향을 주지-u
않도록 하려면 이 작업이 필요합니다. 숨겨진 파일을 추가로 검색합니다.gitignore
. 바이너리도 검색하려면 를 사용하세요.-uu
-uuu
rg --files-without-match -0 'DDD' | xargs -0 rg -l0 'AAAA' | xargs -0 rg -l 'BBB|CCCCC' # if your search terms are literal strings rg --files-without-match -0F 'DDD' | xargs -0 rg -l0F 'AAAA' | xargs -0 rg -lF -e 'BBB' -e 'CCCCC'
rg
여러 줄이 일치하는 경우rg -lUP '(?s)\A(?!.*DDD)(?=.*(BBB|CCCCC)).*AAAA'