awk 'FNR == 1 { f1=f2=f3=0; };
/one/ { f1++ };
/two/ { f2++ };
/three/ { f3++ };
f1 && f2 && f3 {
print FILENAME;
nextfile;
}' *
Jika Anda ingin secara otomatis menangani file gzip, jalankan ini dalam satu lingkaran dengan zcat(lambat dan tidak efisien karena Anda akan forking awkberkali-kali dalam satu lingkaran, sekali untuk setiap nama file) atau menulis ulang algoritma yang sama perldan menggunakan IO::Uncompress::AnyUncompressmodul perpustakaan yang dapat dekompresi beberapa jenis file terkompresi (gzip, zip, bzip2, lzop). atau dalam python, yang juga memiliki modul untuk menangani file terkompresi.
Berikut adalah perlversi yang digunakan IO::Uncompress::AnyUncompressuntuk memungkinkan sejumlah pola dan sejumlah nama file (mengandung teks biasa atau teks terkompresi).
Semua argumen sebelumnya --diperlakukan sebagai pola pencarian. Semua argumen setelah --diperlakukan sebagai nama file. Opsi penanganan yang primitif tetapi efektif untuk pekerjaan ini. Penanganan opsi yang lebih baik (misalnya untuk mendukung -iopsi untuk pencarian case-sensitive) dapat dicapai dengan modul Getopt::Stdatau Getopt::Long.
Jalankan seperti ini:
$ ./arekolek.pl one two three -- *.gz *.txt
1.txt.gz
4.txt.gz
5.txt.gz
1.txt
4.txt
5.txt
(Saya tidak akan membuat daftar file {1..6}.txt.gzdan di {1..6}.txtsini ... mereka hanya berisi beberapa atau semua kata "satu" "dua" "tiga" "empat" "lima" dan "enam" untuk pengujian. File-file yang tercantum dalam output di atas LAKUKAN mengandung ketiga pola pencarian. Uji sendiri dengan data Anda sendiri)
#! /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;
}
}
}
Hash %patternsadalah berisi kumpulan pola lengkap yang file harus mengandung setidaknya satu dari setiap anggota
$_pstringadalah string yang berisi kunci yang diurutkan dari hash itu. String $patternberisi ekspresi reguler pra-dikompilasi juga dibangun dari %patternshash.
$patterndibandingkan dengan setiap baris dari setiap file input (menggunakan /opengubah untuk mengkompilasi $patternhanya sekali seperti yang kita tahu itu tidak akan pernah berubah selama menjalankan), dan map()digunakan untuk membangun hash (% s) yang berisi kecocokan untuk setiap file.
Setiap kali semua pola telah terlihat di file saat ini (dengan membandingkan jika $m_string(kunci yang diurutkan dalam %s) sama dengan $p_string), cetak nama file dan lewati ke file berikutnya.
Ini bukan solusi yang sangat cepat, tetapi tidak terlalu lambat. Versi pertama mengambil 4m58s untuk mencari tiga kata dalam 74MB senilai file log terkompresi (total 937MB terkompresi). Versi saat ini membutuhkan 1m13s. Mungkin ada optimisasi lebih lanjut yang bisa dilakukan.
Salah satu optimasi jelas adalah dengan menggunakan ini dalam hubungannya dengan xargs's -Palias --max-procsuntuk menjalankan beberapa pencarian pada himpunan bagian dari file secara paralel. Untuk melakukan itu, Anda perlu menghitung jumlah file dan membaginya dengan jumlah core / cpus / threads yang dimiliki sistem Anda (dan akhiri dengan menambahkan 1). misalnya ada 269 file yang sedang dicari dalam set sampel saya, dan sistem saya memiliki 6 core (AMD 1090T), jadi:
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[@]}" --
Dengan optimasi itu, hanya butuh 23 detik untuk menemukan semua 18 file yang cocok. Tentu saja, hal yang sama dapat dilakukan dengan solusi lainnya. CATATAN: Urutan nama file yang tercantum dalam output akan berbeda, jadi mungkin perlu disortir sesudahnya jika itu penting.
Seperti dicatat oleh @arekolek, banyak zgreps dengan find -execatau xargsdapat melakukannya secara signifikan lebih cepat, tetapi skrip ini memiliki keuntungan mendukung sejumlah pola untuk mencari, dan mampu menangani beberapa jenis kompresi yang berbeda.
Jika skrip terbatas untuk memeriksa hanya 100 baris pertama dari setiap file, skrip tersebut menjalankan semuanya (dalam 74MB sampel 269 file saya) dalam 0,6 detik. Jika ini berguna dalam beberapa kasus, ini dapat dibuat menjadi opsi baris perintah (misalnya -l 100) tetapi berisiko tidak menemukan semua file yang cocok.
BTW, menurut halaman manual untuk IO::Uncompress::AnyUncompress, format kompresi yang didukung adalah:
Optimasi terakhir (saya harap). Dengan menggunakan PerlIO::gzipmodul (dikemas dalam bahasa debian sebagai libperlio-gzip-perl) alih-alih IO::Uncompress::AnyUncompresssaya punya waktu sekitar 3,1 detik untuk memproses 74MB file log saya. Ada juga beberapa perbaikan kecil dengan menggunakan hash sederhana daripada Set::Scalar(yang juga menghemat beberapa detik dengan IO::Uncompress::AnyUncompressversi).
PerlIO::gzipdirekomendasikan sebagai perl gunzip tercepat di /programming//a/1539271/137158 (ditemukan dengan pencarian google perl fast gzip decompress)
Menggunakan xargs -Pdengan ini tidak meningkatkan sama sekali. Bahkan itu bahkan tampaknya memperlambatnya mulai dari 0,1 hingga 0,7 detik. (Saya mencoba empat kali dan sistem saya melakukan hal-hal lain di latar belakang yang akan mengubah waktunya)
Harganya adalah versi skrip ini hanya dapat menangani file yang di-gzip dan tidak dikompresi. Kecepatan vs fleksibilitas: 3,1 detik untuk versi ini vs 23 detik untuk IO::Uncompress::AnyUncompressversi dengan xargs -Ppembungkus (atau tanpa 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;
}
}
}
gzipramah, cukupzcatfile terlebih dahulu.