하나의 문자열(예:)을 포함하지 않지만 다른 문자열(예:)을 포함하는 파일을 찾아야 합니다 .php
..pl
aaa
bbb
현재 다음 명령을 사용하고 있습니다.
find /path/ \( -iname '*.php*' -or -name '*.pl*' \) -exec sh -c 'grep -l -v "aaa" {} | grep -l "bbb" {}' \; > resulttofile
검색할 파일이 50만개 정도 있는데 알고 싶습니다.
- 내 명령이 올바르게 작동하면 눈 샘플링을 통해 긍정적인 결과를 얻을 수 있습니다.
- 다른 형식(현재 가상 머신에서는 약 2분 정도 소요되지만 더 많은 파일이 추가될 예정)을 사용하거나 대신 또는 둘을 조합하여 사용하는 것이 더 빠를
awk
수sed
있는 경우grep
.grep
시스템은 Debian GNU/Linux입니다.
답변1
귀하의 명령은 작동하지 않습니다. 첫 번째 명령은 grep
일치하지 않는 행을 포함하는 모든 파일을 나열하고 "aaa"
, 두 번째 명령은 처리할 자체 파일을 제공하기 때문에 첫 번째 명령의 출력을 무시합니다. 따라서 여부에 관계없이 grep
일치하는 파일 목록을 가져옵니다. "bbb"
그것들은 포함되어 있습니다 "aaa"
. 줄 일치 ( ) grep
가 없는 경우에만 파일이 나열되도록 요청 하고 결과 파일 목록을 처리하여 두 번째 파일에만 공급해야 합니다 (또는 두 번째 파일이 첫 번째 파일로 시작하도록 해야 합니다)."aaa"
grep -L
xargs
grep
grep
결론은 find
나열된 파일 이름이 셸에 문제를 일으키지 않는 경우에만 작동한다는 것입니다. 특히 {}
주어진 명령에 직접 포함하면 sh -c
파일 이름이 결국 셸 명령으로 해석됩니다(참조"find -exec sh -c"를 사용해도 안전합니까?더 알아보기).
GNU를 사용한다고 가정하면 다음은 더 적은 grep
호출이 필요하고 더 안전합니다.grep
find /path/ \( -iname '*.php*' -o -name '*.pl*' \) -exec grep -LZ aaa {} + |
xargs -r0 grep -l bbb
이것-or
연산자는 GNU 확장입니다 find
. 사용-o
휴대성을 위해.
답변2
테스트되지 않았지만 GNU awk를 사용하여 원하는 대로 작동할 것입니다 nextfile
.ENDFILE
find /path/ \( -iname '*.php*' -or -name '*.pl*' \) -exec awk '
/aaa/{a=1} /bbb/{b=1} a&&b{nextfile} ENDFILE{if (b && !a) print FILENAME; a=b=0}
' {} + > resulttofile
위의 내용은 여러 파일에 대해 awk를 한 번만 호출하므로 효율적입니다.
위는 일반적으로 파일의 여러 패턴을 일치시킨 다음 파일을 완전히 읽은 후 일치된 조합의 결과를 평가하는 방법이지만 다음과 같습니다.@G-Man이 "모니카 복원"이라고 말합니다.에서 언급된코멘트aaa
이 특정한 경우에는 성공 기준이 aaa
존재하지 않기 때문에 일치하는 항목에서 현재 파일 읽기를 중지하여 효율성을 향상시킬 수 있습니다.
/aaa/{a=1; nextfile} /bbb/{b=1} ENDFILE{if (b && !a) print FILENAME; a=b=0}
답변3
find 명령을 사용하여 여러 -exec 지시어(또는 다른 지시어)를 연결할 수 있습니다.
find /path \( -iname '*.php*' -or -name '*.pl*' \) -exec grep -q "bbb" {} ";" \
-exec grep -L "aaa" {} ";" > resulttofile
(줄바꿈은 SE의 레이아웃에 맞추기 위한 것입니다).