awk 'FNR == 1 { f1=f2=f3=0; };
/one/ { f1++ };
/two/ { f2++ };
/three/ { f3++ };
f1 && f2 && f3 {
print FILENAME;
nextfile;
}' *
Otomatik gzip'lenmiş dosyaları işlemek, ya bir döngü içinde bu çalıştırmak istiyorsanız zcat
(eğer bölmek olacak çünkü yavaş ve verimsiz awk
her dosya için bir kere, bir döngü içinde birçok kez) ya da aynı algoritmayı yeniden yazmak perl
ve kullanmak IO::Uncompress::AnyUncompress
kütüphane modülü hangi can sıkıştırılmış dosyaları (gzip, zip, bzip2, lzop) birkaç farklı tür sıkıştırmasını açın. veya sıkıştırılmış dosyaları işlemek için modülleri olan python'da.
Aşağıda , herhangi bir sayıda desene ve herhangi bir sayıda dosya adına (düz metin veya sıkıştırılmış metin içeren) izin vermek için perl
kullanılan bir sürüm bulunmaktadır IO::Uncompress::AnyUncompress
.
Önceki tüm argümanlar --
arama örüntüsü olarak ele alınır. Sonraki tüm argümanlar --
dosya adı olarak kabul edilir. Bu iş için ilkel ama etkili seçenek işleme. Daha iyi seçenek işleme (örn. Büyük / -i
küçük harf duyarlı olmayan aramalar için bir seçeneği desteklemek için) Getopt::Std
veyaGetopt::Long
modülleriyle .
Şu şekilde çalıştırın:
$ ./arekolek.pl one two three -- *.gz *.txt
1.txt.gz
4.txt.gz
5.txt.gz
1.txt
4.txt
5.txt
(Dosyaları listelemeyeceğim {1..6}.txt.gz
ve {1..6}.txt
burada ... test için sadece "bir" "iki" "üç" "dört" "beş" ve "altı" kelimelerinin bir kısmını veya tamamını içeriyorlar. Yukarıdaki çıktıda listelenen dosyalar Arama modellerinin üçünü de YAPIN: Kendi verilerinizle kendiniz test edin)
#! /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;
}
}
}
Karma %patterns
, dosyaların her bir üyeden en az birini içermesi gereken tam desen kümesini içerir ve
$_pstring
bu karma işleminin sıralanmış anahtarlarını içeren bir dizedir. Dize $pattern
, karmadan oluşturulmuş önceden derlenmiş bir normal ifade içerir %patterns
.
$pattern
her girdi dosyasının her satırıyla karşılaştırılır ( çalışma sırasında hiç değişmeyeceğini bildiğimiz gibi yalnızca bir kez /o
derlemek için değiştiriciyi kullanarak $pattern
) vemap()
her dosya için eşleşmeleri içeren bir karma (% s) oluşturmak için kullanılır.
Geçerli desende tüm desenler görüldüğünde ( $m_string
(sıralanan tuşlar %s
) eşit olup olmadığını karşılaştırarak $p_string
), dosya adını yazdırın ve bir sonraki dosyaya geçin.
Bu özellikle hızlı bir çözüm değildir, ancak makul olmayan bir şekilde yavaş değildir. İlk sürüm 4m58 aldı ve 74MB değerinde sıkıştırılmış günlük dosyasında (toplam 937MB sıkıştırılmamış) üç kelime aradı. Bu güncel sürüm 1m13s alır. Muhtemelen yapılabilecek başka optimizasyonlar vardır.
Bariz bir optimizasyon bunu paralel olarak dosyaların alt kümelerinde birden çok arama yapmak için xargs
' -P
aka ' ile birlikte kullanmaktır --max-procs
. Bunu yapmak için, dosya sayısını saymanız ve sisteminizin sahip olduğu çekirdek / cpus / iş parçacığı sayısına bölmeniz (ve 1 ekleyerek yuvarlamanız) gerekir. Örneğin, örnek setimde 269 dosya arandı ve sistemim 6 çekirdeğe (AMD 1090T) sahip, bu yüzden:
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[@]}" --
Bu optimizasyonla, eşleşen 18 dosyanın tümünü bulmak sadece 23 saniye sürdü. Tabii ki, aynı diğer çözümlerden herhangi biri için de yapılabilir. NOT: Çıktıda listelenen dosya adlarının sırası farklı olacaktır, bu nedenle daha sonra sıralanması gerekebilir.
@Arekolek tarafından belirtildiği gibi, veya zgrep
ile birden fazla sfind -exec
xargs
daha hızlı bir şekilde yapabilir, ancak bu komut dosyası, aramak için herhangi bir sayıda deseni destekleme avantajına sahiptir ve birkaç farklı sıkıştırma türüyle başa çıkabilir.
Komut dosyası her dosyanın yalnızca ilk 100 satırını incelemekle sınırlıysa, bunların hepsini (74MB 269 dosya örneğimde) 0.6 saniye içinde çalıştırır. Bu bazı durumlarda yararlıysa, bir komut satırı seçeneğine (örn. -l 100
) Dönüştürülebilir, ancak eşleşen tüm dosyaları bulamama riski vardır .
BTW, kılavuz sayfasına göre IO::Uncompress::AnyUncompress
, desteklenen sıkıştırma formatları şunlardır:
- zlib RFC 1950 ,
- RFC 1951'i söndürün (isteğe bağlı),
- gzip RFC 1952 ,
- zip,
- bzip2,
- lzop,
- lzf,
- lzma,
- xz
Son bir (umarım) optimizasyon. Onun yerine ( PerlIO::gzip
debian olarak paketlenmiş) modülü kullanarak 74MB günlük dosyalarımı işlemek için yaklaşık 3.1 saniyeye kadar zaman aldım . Bunun yerine basit bir karma kullanarak da bazı küçük iyileştirmeler yapıldı (bu da sürümle birkaç saniye tasarruf etti ).libperlio-gzip-perl
IO::Uncompress::AnyUncompress
Set::Scalar
IO::Uncompress::AnyUncompress
PerlIO::gzip
/programming//a/1539271/137158 (için bir google aramasıyla bulundu perl fast gzip decompress
) içinde en hızlı perl gunzip olarak önerildi
xargs -P
Bununla kullanmak hiç iyileştirmedi. Aslında 0.1 ila 0.7 saniye arasında herhangi bir yere yavaşlamış gibi görünüyordu. (Dört çalışmayı denedim ve sistemim arka planda zamanlamayı değiştirecek başka şeyler yapıyor)
Fiyat, komut dosyasının bu sürümünün yalnızca gzip edilmiş ve sıkıştırılmamış dosyaları işleyebilmesidir. Hız ve esneklik: Bu sürüm için 3.1 saniye ve bir IO::Uncompress::AnyUncompress
sürüm için 23 saniyexargs -P
ve sarıcılı (veya 1m13s olmadan 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
Dost olmalarına gerek yok , sadecezcat
önce dosyalar.