서로 다른 두 단어가있는 파일을 검색하는 방법은 무엇입니까?


14

두 단어 인스턴스가 동일한 파일에 존재하는 파일을 검색하는 방법을 찾고 있습니다. 지금까지 다음을 사용하여 검색을 수행했습니다.

find . -exec grep -l "FIND ME" {} \;

내가 겪고있는 문제는 "FIND"와 "ME"사이에 정확히 하나의 공간이 없으면 검색 결과가 파일을 생성하지 않는다는 것입니다. "FIND ME"와 반대로 "FIND"와 "ME라는 단어가 모두 파일에있는 이전 검색 문자열을 어떻게 적용합니까?

AIX를 사용하고 있습니다.


1
단어가 파일의 어느 곳에 나 존재합니까, 아니면 항상 같은 줄에 있습니까?
Sobrique

의도는 같은 줄이었습니다.
채드 해리슨

단어가 같은 줄에있는 경우 대안으로 정규 표현식을 사용하는 것입니다 grep -E/ egrep당신이에 관심이있는 모든 패턴을 설명합니다 (그리고 사용하는 +대신에 ;당신의 발견은 지원이있는 경우 +.
MattBianco

답변:


21

GNU 도구로 :

find . -type f  -exec grep -lZ FIND {} + | xargs -r0 grep -l ME

당신은 표준 적으로 할 수 있습니다 :

find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;

그러나 그것은 파일 당 두 개의 grep을 실행합니다. grep파일 이름에 문자를 허용하면서 많은 수 의 실행을 피하고 이식성을 유지하려면 다음을 수행하십시오.

convert_to_xargs() {
  sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
    {
      if (NR > 1) {
        printf "%s", line
        if (!index($0, "//")) printf "\\"
        print ""
      }
      line = $0
    }'
    END { print line }'
}

find .//. -type f |
  convert_to_xargs |
  xargs grep -l FIND |
  convert_to_xargs |
  xargs grep -l ME

작은 따옴표, 큰 따옴표 및 백 슬래시로 구분할 수있는 단어 목록 find을 xargs (공백 (SPC / TAB / NL 및 일부 구현이있는 로케일의 다른 공란이 예상 됨)가 예상 됨)에 적합한 형식으로 출력을 변환하는 아이디어 xargs공백과 서로 탈출).

일반적으로 find -print파일 이름을 줄 바꿈 문자로 분리하고 파일 이름에서 찾은 줄 바꿈 문자를 이스케이프하지 않기 때문에 의 출력을 후 처리 할 수 ​​없습니다 . 예를 들면 다음과 같습니다.

./a
./b

우리는 그것이라는 하나 개의 파일인지 알 수있는 방법이 없어 한 b라는 디렉토리를 a<NL>.하거나이 두 파일을인지 a하고 b.

사용하여 .//.있기 때문에, //캔에 의해 출력으로 파일 경로 그렇지 않으면 나타나지 않습니다 find(이 빈 이름을 가진 디렉토리 같은 것은 없습니다하기 때문에 /파일 이름에 사용할 수 없습니다), 우리가 알고있는 우리는이 포함 된 라인을 보면 //다음의 것을, 새 파일 이름의 첫 번째 줄 따라서이 awk명령을 사용 하여 줄 바꿈 문자를 제외한 모든 줄 바꿈 문자를 이스케이프 할 수 있습니다 .

위의 예 find를 보면 첫 번째 경우 (한 파일)로 출력됩니다.

.//a
./b

어느 awk가 탈출합니까?

.//a\
./b

그래서 xargs그것은 그것을 하나의 논쟁으로 간주합니다. 두 번째 경우 (파일 두 개) :

.//a
.//b

어느 awk것이 그대로 xargs남았는지 두 가지 주장이 있습니다.


왜 사용하지 find ... -print0하고 grep --null대신?
15:32에

@ razzed, 그게 무슨 뜻인지 잘 모르겠습니다. grep --null(일명 -Z)는 첫 번째에서 사용되지만 GNU 확장입니다. -print0(다른 GNU 확장)은 여기서 도움이되지 않습니다.
Stéphane Chazelas 2016 년

감사. 셸 코드를 검색 디렉토리를 명령 줄의 인수로 사용하는 스크립트로 래핑하고 싶습니다. .//.아직 무엇을 의미 하는지 잘 모르겠 으며 명령 줄에서 인수를 수락하도록 어떻게 수정할 수 있는지 궁금합니다 $1.
Tim

감사. 명령에서는 사용할 필요가 -print0find-0함께 xargs?
Tim

@Tim, 무슨 뜻인지 잘 모르겠습니다. 나는 find -print0대답의 어느 곳에서도 사용하지 않습니다 .
Stéphane Chazelas

8

파일이 하나의 디렉토리에 자신의 이름을 공백, 탭, 개행 문자가 포함되지 않은 경우 *, ?[문자와 함께 시작하지 -않으며 .,이 ME가 포함 된 파일의 목록을 얻을 것이다, 다음 사람에게 그 아래로 범위를 좁힐 그 FIND도 포함합니다.

grep -l FIND `grep -l ME *`

더 많은 투표가 필요합니다 !! "허용 된"답변보다 훨씬 더 우아합니다. 나를 위해 일했다.
roblogic

grep -l CategoryLinearAxis `grep -l labelJsFunction *`두 속성이 모두있는 파일을 찾는 동안 방금 수행 했습니다. 그것을하는 완벽한 방법입니다. +1
WEBjuju

3

로에게 awk당신은 또한 실행할 수 있습니다 :

find . -type f  -exec awk 'BEGIN{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; END{if (cx > 0 && cy > 0) print FILENAME}' {} \;

및를 사용 cx하여 각각 cy일치하는 행을 계산합니다 . 에서는 블록 모두 카운터> 0 인 경우, 인쇄 . 이것은 다음과 같이 더 빠르고 효율적입니다 .FINDMEENDFILENAME
gnu awk

find . -type f  -exec gawk 'BEGINFILE{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; ENDFILE{if (cx > 0 && cy > 0) print FILENAME}' {} +

2

또는 사용 egrep -e또는grep -E 이것을 좋아하십시오 :

find . -type f -exec egrep -le '(ME.*FIND|FIND.*ME)' {} \;

또는

find . -type f -exec grep -lE '(ME.*FIND|FIND.*ME)' {} +

+차종은 (지원되는 경우) 찾을 명령 존재에 인수로 이름을 여러 개의 파일 (경로)를 추가-exec 에디션. 이렇게하면 프로세스가 절약되고 \;발견 된 각 파일에 대해 명령을 한 번 호출하는 것보다 훨씬 빠릅니다 .

-type f 디렉토리와의 충돌을 피하기 위해 파일과 만 일치합니다.

'(ME.*FIND|FIND.*ME)'"ME"와 "FIND"또는 "FIND"와 "ME"를 포함하는 모든 행과 일치하는 정규식입니다. 쉘이 특수 문자를 해석하지 못하도록 작은 따옴표.

a를 -i받는grep대소 문자를 구분하지 않으려면 명령에 .

"FIND"가 "ME"앞에 오는 행만 일치 시키려면을 사용하십시오 'FIND.*ME'.

단어 사이에 공백 (1 개 이상 필요)을 요구하려면 : 'FIND +ME'

단어 사이에 공백 (0 이상)을 허용하려면 다음을 수행하십시오. 'FIND *ME'

조합은 정규 표현식으로 끝이 없으며 한 번에 한 행 씩만 일치하는 데 관심이 있다면 egrep은 매우 강력합니다.


대부분의 greps가 "-r"을 지원하지 않습니까? 그러면 "찾기"가 제거되지만 검색중인 트리에 소켓 또는 일반 파일이 아닌 다른 파일이있을 수 있습니다.
stolenmoment

OP는 AIX를 사용 find하며 문제가 있습니다.
MattBianco

0

허용 된 답변을 보면 필요한 것보다 더 복잡해 보입니다. 의 GNU 버전 findgrepxargs지원 NULL로 끝나는 문자열. 다음과 같이 간단합니다.

find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l ME

find원하는 파일로 필터링하도록 명령을 수정할 수 있으며 모든 문자가 포함 된 파일 이름과 함께 작동합니다. 추가 된 sed구문 분석 없이 파일을 추가로 처리 --null하려면 마지막 파일에 다른 파일을 추가하십시오grep

find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l --null ME | xargs -0 echo

그리고 함수로서 :

find_strings() {
    find . -type f -print0 | xargs -0 grep -l --null "$1" | xargs -0 grep -l "$2"
}

이러한 도구의 GNU 버전을 실행하지 않는 경우 허용되는 대답을 사용하십시오.


1
--null, --print0, -0모든 GNU 확장이다. 현재 일부 구현은 다른 구현에서 볼 수 있지만 POSIX 또는 Unix 표준이 아닌 이식성이 없습니다.
Stéphane Chazelas 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.