awk 'FNR == 1 { f1=f2=f3=0; };
/one/ { f1++ };
/two/ { f2++ };
/three/ { f3++ };
f1 && f2 && f3 {
print FILENAME;
nextfile;
}' *
หากคุณต้องการจัดการไฟล์ gzipped โดยอัตโนมัติให้รันไฟล์นี้ในลูปด้วยzcat
(ช้าและไม่มีประสิทธิภาพเพราะคุณจะฟอร์กawk
หลายครั้งในลูปหนึ่งครั้งสำหรับแต่ละชื่อไฟล์) หรือเขียนอัลกอริทึมเดียวกันในperl
และใช้IO::Uncompress::AnyUncompress
โมดูลห้องสมุดที่สามารถ ขยายขนาดไฟล์บีบอัดหลายชนิด (gzip, zip, bzip2, lzop) หรือในไพ ธ อนซึ่งมีโมดูลสำหรับจัดการไฟล์บีบอัด
ต่อไปนี้เป็นperl
เวอร์ชันที่ใช้IO::Uncompress::AnyUncompress
สำหรับอนุญาตรูปแบบจำนวนเท่าใดก็ได้และชื่อไฟล์จำนวนเท่าใดก็ได้ (มีทั้งข้อความธรรมดาหรือข้อความที่บีบอัด)
args ทั้งหมดก่อน--
จะถือเป็นรูปแบบการค้นหา args ทั้งหมดหลังจากนั้น--
จะถือเป็นชื่อไฟล์ การจัดการตัวเลือกดั้งเดิม แต่มีประสิทธิภาพสำหรับงานนี้ การจัดการตัวเลือกที่ดีกว่า (เช่นเพื่อสนับสนุน-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
(ฉันจะไม่แสดงรายการไฟล์{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
(คีย์ที่เรียงใน%s
) เท่ากับ$p_string
) ให้พิมพ์ชื่อไฟล์และข้ามไปที่ไฟล์ถัดไป
นี่ไม่ใช่วิธีแก้ปัญหาที่รวดเร็วโดยเฉพาะ แต่ไม่ช้าอย่างไร้เหตุผล รุ่นแรกใช้เวลา 4m58s ในการค้นหาคำสามคำในไฟล์บันทึกที่ถูกบีบอัด 74MB (รวม 937MB ที่ไม่บีบอัด) รุ่นปัจจุบันนี้ใช้เวลา 1m13s อาจมีการเพิ่มประสิทธิภาพเพิ่มเติมที่สามารถทำได้
หนึ่งในการเพิ่มประสิทธิภาพที่เห็นได้ชัดคือการใช้นี้ร่วมกับxargs
's -P
aka --max-procs
ที่จะเรียกใช้การค้นหาหลายคนบนย่อยของไฟล์ในแบบคู่ขนาน ในการทำเช่นนั้นคุณต้องนับจำนวนไฟล์และหารด้วยจำนวนแกน / cpus / เธรดที่ระบบของคุณมี (และปัดเศษขึ้นโดยการเพิ่ม 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[@]}" --
ด้วยการปรับให้เหมาะสมนั้นใช้เวลาเพียง 23 วินาทีในการค้นหาไฟล์ที่ตรงกันทั้งหมด 18 ไฟล์ แน่นอนว่าสามารถทำได้ด้วยวิธีการแก้ปัญหาอื่น ๆ หมายเหตุ: ลำดับของชื่อไฟล์ที่แสดงในเอาท์พุทจะแตกต่างกันดังนั้นอาจจำเป็นต้องเรียงลำดับหลังจากนั้นหากจำเป็น
ดังที่บันทึกไว้โดย @arekolek หลาย ๆzgrep
s ด้วยfind -exec
หรือxargs
สามารถทำได้เร็วขึ้นอย่างมาก แต่สคริปต์นี้มีข้อดีของการสนับสนุนรูปแบบจำนวนเท่าใดก็ได้ที่จะค้นหาและมีความสามารถในการจัดการกับการบีบอัดหลายประเภท
หากสคริปต์ถูก จำกัด ให้ตรวจสอบเพียง 100 บรรทัดแรกของแต่ละไฟล์สคริปต์จะดำเนินการผ่านทั้งหมด (ในตัวอย่าง 74MB ของฉันที่ 269 ไฟล์) ใน 0.6 วินาที ถ้าเรื่องนี้จะเป็นประโยชน์ในบางกรณีก็อาจจะทำให้เป็นตัวเลือกบรรทัดคำสั่ง (เช่น-l 100
) แต่มันก็มีความเสี่ยงจากการไม่ได้หาทุกไฟล์ที่ตรงกัน
BTW อ้างอิงจากหน้า man สำหรับIO::Uncompress::AnyUncompress
รูปแบบการบีบอัดที่รองรับคือ:
การเพิ่มประสิทธิภาพครั้งสุดท้าย (ฉันหวังว่า) โดยใช้PerlIO::gzip
โมดูล (บรรจุเป็นเดเบียนเป็นlibperlio-gzip-perl
) แทนIO::Uncompress::AnyUncompress
ฉันได้เวลาลงไปประมาณ3.1 วินาทีสำหรับการประมวลผลล็อกไฟล์ 74MB ของฉัน นอกจากนั้นยังมีการปรับปรุงบางขนาดเล็กโดยใช้แฮชที่เรียบง่ายมากกว่าSet::Scalar
(ซึ่งยังบันทึกไม่กี่วินาทีกับIO::Uncompress::AnyUncompress
รุ่น)
PerlIO::gzip
ได้รับการแนะนำให้เป็น gunzip ที่เร็วที่สุดใน/programming//a/1539271/137158 (พบกับการค้นหาโดย google perl fast gzip decompress
)
ใช้xargs -P
กับสิ่งนี้ไม่ได้ปรับปรุงเลย ในความเป็นจริงมันก็ดูเหมือนว่าจะชะลอตัวลงได้ทุกที่ตั้งแต่ 0.1 ถึง 0.7 วินาที (ฉันลองสี่วิ่งและระบบของฉันทำสิ่งอื่น ๆ ในพื้นหลังซึ่งจะเปลี่ยนเวลา)
ราคาคือสคริปต์เวอร์ชันนี้สามารถรองรับไฟล์ gzipped และ uncompressed เท่านั้น ความเร็วเทียบกับความยืดหยุ่น: 3.1 วินาทีสำหรับรุ่นนี้เทียบกับ 23 วินาทีสำหรับIO::Uncompress::AnyUncompress
รุ่นที่มีเครื่องxargs -P
ห่อหุ้ม (หรือไม่มี 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
ไฟล์ก่อน