다음 내용이 포함된 파일이 있습니다.
$ 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 모드에서 텍스트의 시작과 끝을 표시합니다. 즉, 문자열에 존재할 수 있는 모든 메타 문자는 특별한 의미를 비활성화하기 위해 인용됩니다. "인용 메타문자"를 확인하고 검색하여 자세히 알아보세요.\E
qr//
man perlre
perldoc -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 도구를 사용하여 여러 줄 고정 문자열 검색 및 바꾸기이와 같은 더 많은 여러 줄 작업의 경우.