awk 'FNR == 1 { f1=f2=f3=0; };
/one/ { f1++ };
/two/ { f2++ };
/three/ { f3++ };
f1 && f2 && f3 {
print FILENAME;
nextfile;
}' *
gzip으로 압축 된 파일을 자동으로 처리하려면이 파일을 루프 zcat
( awk
루프에서 여러 번 포크하므로 각 파일 이름마다 한 번씩)하므로 동일한 알고리즘을 다시 작성 perl
하고 IO::Uncompress::AnyUncompress
라이브러리 모듈을 사용할 수 있습니다. 여러 종류의 압축 파일 (gzip, zip, bzip2, lzop)을 압축 해제하십시오. 또는 파이썬에서는 압축 파일을 처리하기위한 모듈도 있습니다.
다음은 여러 패턴과 파일 이름 (일반 텍스트 또는 압축 텍스트 포함)을 허용 perl
하는 데 사용 되는 버전입니다 IO::Uncompress::AnyUncompress
.
이전의 모든 인수 --
는 검색 패턴으로 취급됩니다. 이후의 모든 인수 --
는 파일 이름으로 취급됩니다. 이 작업에 대한 기본적이지만 효과적인 옵션 처리. 또는 모듈을 -i
사용하면 더 나은 옵션 처리 (예 : 대소 문자를 구분하지 않는 검색을위한 옵션 지원 )를 수행 할 수 있습니다 .Getopt::Std
Getopt::Long
다음과 같이 실행하십시오.
$ ./arekolek.pl one two three -- *.gz *.txt
1.txt.gz
4.txt.gz
5.txt.gz
1.txt
4.txt
5.txt
(I는 목록 파일하지 않습니다 {1..6}.txt.gz
와 {1..6}.txt
여기가 ... 그들은 단지 테스트를위한 단어 "하나", "둘" "셋" "네" "오"와 "육"의 일부 또는 전부를 포함한다. 출력 위에 나열된 파일을 세 가지 검색 패턴을 모두 포함하십시오 (자신의 데이터로 직접 테스트)
#! /usr/bin/perl
use strict;
use warnings;
use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ;
my %patterns=();
my @filenames=();
my $fileargs=0;
# all args before '--' are search patterns, all args after '--' are
# filenames
foreach (@ARGV) {
if ($_ eq '--') { $fileargs++ ; next };
if ($fileargs) {
push @filenames, $_;
} else {
$patterns{$_}=1;
};
};
my $pattern=join('|',keys %patterns);
$pattern=qr($pattern);
my $p_string=join('',sort keys %patterns);
foreach my $f (@filenames) {
#my $lc=0;
my %s = ();
my $z = new IO::Uncompress::AnyUncompress($f)
or die "IO::Uncompress::AnyUncompress failed: $AnyUncompressError\n";
while ($_ = $z->getline) {
#last if ($lc++ > 100);
my @matches=( m/($pattern)/og);
next unless (@matches);
map { $s{$_}=1 } @matches;
my $m_string=join('',sort keys %s);
if ($m_string eq $p_string) {
print "$f\n" ;
last;
}
}
}
해시 %patterns
는 파일에 각 멤버 중 적어도 하나를 포함해야하는 완전한 패턴 세트가 포함되어 있으며
$_pstring
해당 해시의 정렬 된 키를 포함하는 문자열입니다. 문자열 $pattern
에는 %patterns
해시 에서 빌드 된 사전 컴파일 된 정규식이 포함 됩니다.
$pattern
는 각 입력 파일의 각 줄과 비교되며 ( /o
수정자를 사용하여 $pattern
실행 중에 변경되지 않는다는 것을 한 번만 컴파일 map()
) 각 파일의 일치 항목을 포함하는 해시 (% s)를 작성하는 데 사용됩니다.
현재 파일에 모든 패턴이 표시 될 때마다 $m_string
((정렬 키가 if %s
와 같은지 비교 $p_string
)) 파일 이름을 인쇄하고 다음 파일로 건너 뜁니다.
이것은 특히 빠른 해결책은 아니지만 부당하게 느리지 않습니다. 첫 번째 버전은 74MB 상당의 압축 로그 파일에서 총 3 개의 단어를 검색하는 데 4m58s가 소요되었습니다 (총 937MB의 비 압축). 이 현재 버전은 1m13s가 걸립니다. 추가 최적화가 이루어질 수 있습니다.
한 가지 분명한 최적화와 함께이를 사용하는 것입니다 xargs
의 -P
일명 --max-procs
병렬 파일의 하위 집합에서 여러 검색을 실행합니다. 그렇게하려면 파일 수를 세고 시스템에있는 코어 / CPU / 스레드 수로 나눈 다음 1을 더해서 반올림해야합니다. 예를 들어, 샘플 세트에서 269 개의 파일이 검색되고 있으며 시스템에는 6 개의 코어 (AMD 1090T)가 있습니다.
patterns=(one two three)
searchpath='/var/log/apache2/'
cores=6
filecount=$(find "$searchpath" -type f -name 'access.*' | wc -l)
filespercore=$((filecount / cores + 1))
find "$searchpath" -type f -print0 |
xargs -0r -n "$filespercore" -P "$cores" ./arekolek.pl "${patterns[@]}" --
이 최적화를 통해 일치하는 18 개의 파일을 모두 찾는 데 23 초 밖에 걸리지 않았습니다. 물론 다른 솔루션에서도 동일하게 수행 할 수 있습니다. 참고 : 출력에 나열된 파일 이름의 순서가 다르므로 중요한 경우 나중에 정렬해야합니다.
@arekolek에서 언급 한 바와 같이, 여러 zgrep
과의 find -exec
또는 xargs
매우 빠르게 할 수 있지만,이 스크립트를 검색 할 패턴의 수를 지원하는 장점을 가지고 있으며, 압축의 여러 가지 유형을 처리 할 수 있습니다.
스크립트가 각 파일의 처음 100 줄만 검사하도록 제한되어 있으면 0.6 초 안에 모든 파일 (74MB의 269 파일 샘플)을 실행합니다. 이것이 어떤 경우에 유용한 경우, 명령 행 옵션 (예 :)으로 만들 수 -l 100
있지만 일치하는 파일 을 모두 찾지 못할 수도 있습니다.
BTW에 대한 매뉴얼 페이지에 따르면 IO::Uncompress::AnyUncompress
지원되는 압축 형식은 다음과 같습니다.
마지막으로 (나는 희망) 최적화. 대신 PerlIO::gzip
데비안 패키지로 모듈 을 사용하면 74MB의 로그 파일을 처리하는 데 약 3.1 초가 소요 됩니다. 간단한 해시를 사용하는 것보다는 약간의 개선이있었습니다 ( 버전 으로 몇 초도 절약되었습니다 ).libperlio-gzip-perl
IO::Uncompress::AnyUncompress
Set::Scalar
IO::Uncompress::AnyUncompress
PerlIO::gzip
/programming//a/1539271/137158 에서 가장 빠른 perl gunzip으로 권장되었습니다 (Google 검색에서 찾음 perl fast gzip decompress
)
xargs -P
이것과 함께 사용하면 전혀 향상되지 않았습니다. 실제로 0.1 초에서 0.7 초까지 속도가 느려지는 것처럼 보였습니다. (나는 네 번의 달리기를 시도했고 내 시스템은 백그라운드에서 다른 것들을 수행하여 타이밍을 바꿀 것입니다)
가격은이 버전의 스크립트는 압축 및 압축되지 않은 파일 만 처리 할 수 있다는 것입니다. 속도 대 유연성 :이 버전의 경우 3.1 초 IO::Uncompress::AnyUncompress
, xargs -P
래퍼가 있는 버전의 경우 23 초 (또는 1m13s없는 경우 xargs -P
).
#! /usr/bin/perl
use strict;
use warnings;
use PerlIO::gzip;
my %patterns=();
my @filenames=();
my $fileargs=0;
# all args before '--' are search patterns, all args after '--' are
# filenames
foreach (@ARGV) {
if ($_ eq '--') { $fileargs++ ; next };
if ($fileargs) {
push @filenames, $_;
} else {
$patterns{$_}=1;
};
};
my $pattern=join('|',keys %patterns);
$pattern=qr($pattern);
my $p_string=join('',sort keys %patterns);
foreach my $f (@filenames) {
open(F, "<:gzip(autopop)", $f) or die "couldn't open $f: $!\n";
#my $lc=0;
my %s = ();
while (<F>) {
#last if ($lc++ > 100);
my @matches=(m/($pattern)/ogi);
next unless (@matches);
map { $s{$_}=1 } @matches;
my $m_string=join('',sort keys %s);
if ($m_string eq $p_string) {
print "$f\n" ;
close(F);
last;
}
}
}
gzip
친숙 할 필요는 없습니다zcat
. 파일 만 있으면 됩니다.