중첩된 파이프 grep은 "(표준 입력)" 문자열을 생성합니다.

중첩된 파이프 grep은 "(표준 입력)" 문자열을 생성합니다.

나는 다음과 같이 중첩된 grep을 수행하고 있습니다.

grep -ir "Some string" . |grep "Another string I want to find in the other grep's results"

이것은 예상한 대로 정확히 작동하지만(두 번째 grep에서 첫 번째 grep의 결과도 필터링했습니다), 일단 "-l" 옵션을 추가하면 두 번째 grep에서 파일 목록만 가져오고 아무것도 얻지 못합니다. 미만.

grep -ir "Some string" . |grep -l "Another string I want to find in the other grep's results"

그러면 다음과 같은 출력이 생성됩니다.

(standard input)

파일 목록만 원할 때는 파이핑이 작동하지 않는 것 같습니다. 다른 옵션이 있나요?

답변1

옵션을 사용 -l하면 grep유틸리티가 지정된 패턴을 포함하는 파일 이름만 인쇄합니다. 내 시스템 설명서에는 이 옵션에 대해 다음과 같이 나와 있습니다.

선택한 행을 포함하는 파일 이름만 표준 출력에 기록됩니다. grep은 일치하는 항목을 찾을 때까지만 파일을 검색하므로 검색 비용이 잠재적으로 더 저렴해집니다. 검색된 각 파일에 대해 경로 이름이 한 번씩 나열됩니다. 표준 입력을 검색하면 "(표준 입력)"이라는 문자열이 기록됩니다.

파이프의 두 번째 항목은 grep파일이 아닌 표준 입력에서 읽기 때문에 표준 입력 스트림에 도착했을 때 외에는 데이터가 어디서 왔는지 알 수 없습니다. 이것이 바로 텍스트 문자열을 반환하는 이유입니다 (standard input). 대회장과 가장 가까운 곳입니다.

첫 번째 패턴의 두 패턴을 결합합니다 grep(여기서하다어떤 파일을 찾고 있는지 알아보려면), 다음을 참조하세요.여러 AND 패턴으로 grep을 실행하는 방법은 무엇입니까?

답변2

"cut"을 사용하여 ":" 뒤의 문자열을 제거하면 파일 부분을 얻게 됩니다(파일 경로에 콜론이나 개행 문자가 포함되어 있지 않고 두 번째 패턴 자체와 일치하지 않는다고 가정).

grep -ir "Some string" . |grep "Another string I want to find in the other grep's results" | cut -d ":" -f 1

중복이 발생하면 "uniq"를 사용하십시오.

grep -ir "string1" . | grep "string2" | cut -d: -f1 | uniq

답변3

grep( 귀하의 방법처럼 두 번째 항목이 파일 이름이나 두 가지 모두가 아닌 줄의 내용과 일치하기를 원한다고 가정합니다 .)

POSIX적으로:

find . -type f -exec awk '
  FNR == 1 {found = 0}
  !found && tolower($0) ~ /some string/ && /other string/ {
    print FILENAME
    found = 1
    nextfile
  }' {} +

문제 found는 awk 구현이 아직 지원되지 않는다는 것입니다 nextfile( nextfile따라서 no-op는 어디에 있습니까). awk구현이 이를 지원한다는 것을 알고 있는 경우 nextfile다음과 같이 단순화할 수 있습니다.

 find . -type f -exec awk 'tolower($0) ~ /some string/ && /other string/ {
    print FILENAME; nextfile}' {} +

grep한 일치 항목은 대소문자를 구분하지만 다른 일치 항목은 구분하지 않기를 원하므로 PCRE 지원과 함께 GNU를 사용하십시오.

grep -rlP '^(?=.*(?i:some string))(?=.*other string)' .

(?=...)펄이다시야운영자. (?i:pattern)열려 있는대소문자를 구분하지 않는 일치단지 pattern. 따라서 여기서 우리는 ^줄의 시작 부분( ) 뒤에 임의의 수의 문자( .*)와 (대소문자 구분 안 함)이 있고 그(줄의 시작 부분) 뒤에 임의의 수의 문자와 (대소 some string문자 구분)이 있는 한 줄의 시작 부분에서 일치합니다. other string예민한) .

grep해당 을 지원하지 않는 경우 -P이 명령을 사용하거나 pcregrep( grep -rlP로 대체 pcregrep -rl), 패턴이 겹치지 않는 경우 다음을 수행할 수 있습니다.

grep -rl -e '[sS][oO][mM][eE] [sS][tT][rR][iI][nN][gG].*other string' \
         -e 'other string.*[sS][oO][mM][eE] [sS][tT][rR][iI][nN][gG]' .

또는 두 일치 항목의 대소문자를 구분하지 않아도 되는 경우:

grep -ril -e 'some string.*other string' \
          -e 'other string.*some string' .

답변4

이는 제공된 모든 솔루션 중 가장 짧은 솔루션입니다.

find . -type f -exec perl -lne '
   /Some string/i and /other string/ and print($ARGV),close(*ARGV);
' {} +

grep -irZ "Some string" . |
perl -lsF'/\n/' -0ne '
   s/^/\n/ if $. == 1; s/$/\n/ if eof;

   $. == 1 and $prev = $F[1],next;
   push @{$h{$prev}}, $F[0];
   $prev = $F[1];

   END {
      grep($_ =~ /\Q${str2}/, @{$h{$_}}) and print for keys %h;
   }
' -- -str2="Another string"

작동 방식: 여기에서는 grepa가 먼저 실행되어 현재 디렉터리에서 "특정 문자열"을 검색하고 recursive주어진 옵션 으로 인해 null로 구분된() 레코드를 생성합니다 .case-insensitive\0-Zgrep

각 레코드에는 파일 이름과 일치하는 줄이 포함되어 있습니다. 유일한 문제는 grep이 \0일치하는 줄 뒤에 a를 추가하는 동작이 없기 때문에 정렬이 일관성이 없다는 것입니다. 이 제한 사항을 해결하기 위해 우리는 Perlnull로 구분된 레코드를 읽고 이러한 레코드를 분할하여 \n파일 이름과 줄을 구분하는 이점을 활용합니다 .

따라서 관련될 수 있는 파일 이름 유형에 제한을 두지 않지만 \0어쨌든 금지됩니다.

관련 정보