전체 줄이 일치하는 파일 찾기

전체 줄이 일치하는 파일 찾기

다음 내용이 포함된 파일이 있습니다.

$ cat compromised_header.txt
some unique string 1
some other unique string 2
another unique string 3

위 파일의 모든 줄이 정확히 동일한 순서로 있고 줄 사이에 중간 줄이 없는 모든 파일을 찾고 싶습니다.

입력 파일 예:

$ cat a-compromised-file.txt
some unique string 1
some other unique string 2
another unique string 3
unrelated line x
unrelated line y
unrelated line z

나는 다음을 사용해 보았습니다 grep.

grep -rlf compromised_header.txt dir/

하지만 다음과도 일치하기 때문에 예상되는 파일을 제공하는지 잘 모르겠습니다.

some unique string 1
unrelated line x
unrelated line y
unrelated line z

답변1

다음을 지원하는 awk를 사용하십시오 nextfile.

NR == FNR {
  a[++n]=$0; next
}
$0 != a[c+1] && (--c || $0!=a[c+1]) {
  c=0; next
}
++c >= n {
  print FILENAME; c=0; nextfile
}

재귀 의 경우 find:

find dir -type f -exec gawk -f above.awk compromised_header.txt {} +

아니면 다음과 같이 작동할 수도 있습니다.

pcregrep -rxlM "$( perl -lpe '$_=quotemeta' compromised_header.txt )" dir

pcregrep --fixed-strings--multiline.

Perl이 후루룩 모드에 있는 경우(메모리에 맞지 않을 정도로 큰 파일에는 적합하지 않음):

find dir -type f -exec perl -n0777E 'BEGIN {$f=<>} say $ARGV if /^\Q$f/m
' compromised_header.txt {} +

답변2

grep한 줄만 일치시키는 것 보다 더 강력한 것을 사용해야 합니다 .

perl이러한 종류의 작업에 이상적인 다중 행 일치를 수행할 수 있으며 이를 결합하여 find검색할 파일 목록을 생성할 수 있습니다.

find dir/ -type f -iname '*.txt' -exec perl -e '
    local $/;    # slurp in entire files, instead of one line at a time

    my $firstfile = shift @ARGV;         # get name of the first file
    open(F,"<",$firstfile) or die "Error opening $firstfile: $!";
    my $first = <F>;                     # read it in
    close(F);
    my $search = qr/\Q$first\E/;         # compile to a fixed-string RE

    # now read in remaining files and see if they match
    while(<>) {
      next if ($ARGV eq $firstfile);
      if (m/$search/m) {
        print $ARGV,"\n";
      };
    }' ./compromised_header.txt {} +

dir/그러면 첫 번째 파일("compromised_header.txt")의 정확한 텍스트가 포함된 모든 *.txt 파일의 파일 이름이 인쇄됩니다.

노트:

  • 연산자는 qr//정규식을 컴파일합니다. 주요 용도는 루프에서 사용하기 전에 RE를 미리 컴파일하여 모든 루프가 다시 컴파일되지 않도록 하여 시간과 CPU 사이클을 낭비하는 것입니다.

  • 작업에 사용된 및는 \Q고정 문자열로 해석되도록 고안된 RE 모드에서 텍스트의 시작과 끝을 표시합니다. 즉, 문자열에 존재할 수 있는 모든 메타 문자는 특별한 의미를 비활성화하기 위해 인용됩니다. "인용 메타문자"를 확인하고 검색하여 자세히 알아보세요.\Eqr//man perlreperldoc -f quotemeta

보기 흉하고 복잡하며 읽기 어려운 한 줄짜리 스크립트처럼 보이면 다음과 같은 것을 독립 실행형 스크립트로 시도해 보십시오.

#!/usr/bin/perl

local $/;    # slurp in entire files, instead of one line at a time

my $firstfile = shift @ARGV;         # get name of the first file
open(F,"<",$firstfile) or die "Error opening $firstfile: $!";
my $first = <F>;                     # read it in
close(F);
my $search = qr/\Q$first\E/;         # compile to a fixed-string RE

# now read in remaining files and see if they match
while(<>) {
  next if ($ARGV eq $firstfile);
  if (m/$search/m) {
    print $ARGV,"\n";
  };
}

예를 들어 다른 이름으로 저장 check.pl하고 실행 가능하게 만듭니다 chmod +x check.pl. 그런 다음 다음을 실행하십시오.

find dir/ -type f -iname '*.txt' \
  -exec ./check.pl ./compromised_header.txt {} +

답변3

PCRE -P 모드로 GNU grep을 사용하는 경우 slurp 모드 -z 및 재귀적으로 -r list -l 정규식 $re와 일치하는 파일을 작동할 수 있습니다. 정규식은 참조 헤더 파일에서 작성되며 Perl 정규식 컨텍스트에서 모든 특수 문자를 이스케이프합니다.

re=$(< compromised_header.txt perl -lpe '$_=quotemeta')
re=${re//[${IFS#??}]/\\n}
grep -lrzP "(?m)^$re" .

답변4

검색 문자열에 여러 개의 후행 줄 바꿈 또는 ASCII NUL 문자가 없다고 가정합니다(참조파일을 쉘 변수로 읽을 때의 함정자세한 내용은) 다음을 사용할 수 있습니다.립그렙:

rg -lUF "$(< compromised_header.txt)" dir/

-F파일 내용을 정규식으로 처리하지 않고 문자 그대로 검색하려면 옵션을 사용하세요.

-U여러 줄 검색을 활성화하는 옵션

rg기본적으로 재귀적으로 검색하지만 기본적으로 스마트 필터링도 수행합니다( .gitignore규칙 준수, 숨겨진 파일/폴더 무시, 바이너리 무시 등). -uuu처럼 동작하게 하려면 사용하십시오 grep -r.


내 블로그 게시물을 참조하세요cli 도구를 사용하여 여러 줄 고정 문자열 검색 및 바꾸기이와 같은 더 많은 여러 줄 작업의 경우.

관련 정보