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
किसी भी संख्या में पैटर्न और किसी भी फ़ाइल नाम (किसी भी सादे पाठ या संपीड़ित पाठ) की अनुमति देने के लिए उपयोग करता है।
पहले सभी आर्गों --
को खोज पैटर्न के रूप में माना जाता है। सभी आर्ग के बाद --
फाइलनाम के रूप में माना जाता है। इस काम के लिए आदिम लेकिन प्रभावी विकल्प से निपटने। बेहतर विकल्प से निपटने (जैसे -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
है एक स्ट्रिंग है जिसमें उस .h की सॉर्ट की हुई कुंजी होती है। स्ट्रिंग $pattern
में %patterns
हैश से निर्मित एक पूर्व संकलित नियमित अभिव्यक्ति भी होती है ।
$pattern
प्रत्येक इनपुट फ़ाइल की प्रत्येक पंक्ति के खिलाफ तुलना की जाती है ( केवल एक बार /o
संकलित करने के लिए संशोधक का उपयोग करके $pattern
जैसा कि हम जानते हैं कि यह रन के दौरान कभी नहीं बदलेगा), और map()
प्रत्येक फ़ाइल के लिए मैचों वाले हैश (% s) बनाने के लिए उपयोग किया जाता है।
जब भी वर्तमान फ़ाइल में सभी पैटर्न देखे गए हैं (यदि $m_string
(सॉर्ट की गई कुंजियों के %s
बराबर है तो $p_string
) की तुलना करके , फ़ाइल नाम प्रिंट करें और अगली फ़ाइल पर जाएं।
यह विशेष रूप से तेज़ समाधान नहीं है, लेकिन अनुचित रूप से धीमा नहीं है। पहले संस्करण में 4 एमबी 58 सेकेंड की तीन फाइलों को खोजने के लिए 74 एमबी मूल्य की कंप्रेस्ड लॉग फाइल (कुल 937MB असम्पीडित) की तलाश की गई। यह वर्तमान संस्करण 1m13s लेता है। शायद आगे और भी आशाएँ हैं जिन्हें बनाया जा सकता है।
एक स्पष्ट अनुकूलन के साथ संयोजन के रूप में इस का उपयोग करने के लिए है xargs
's -P
उर्फ --max-procs
समानांतर में फ़ाइलों के सबसेट पर एक से अधिक खोजें चलाने के लिए। ऐसा करने के लिए, आपको फ़ाइलों की संख्या की गणना करने की आवश्यकता है और आपके सिस्टम में कोर / cpus / थ्रेड्स की संख्या से विभाजित करें (और 1 जोड़कर गोल करें)। उदाहरण के लिए मेरे सैंपल सेट में 269 फाइलें खोजी गईं, और मेरे सिस्टम में 6 कोर (एएमडी 1090 टी) हैं, इसलिए:
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 सेकंड में उन सभी (269 फाइलों के मेरे 74 एमबी नमूने में) के माध्यम से चलती है। यदि यह कुछ मामलों में उपयोगी है, तो इसे कमांड लाइन विकल्प (जैसे -l 100
) में बनाया जा सकता है, लेकिन इसमें सभी मिलान फ़ाइलों को नहीं खोजने का जोखिम है ।
BTW, के लिए मैन पेज के अनुसार IO::Uncompress::AnyUncompress
, संपीड़न प्रारूप समर्थित हैं:
एक अंतिम (मुझे आशा है) अनुकूलन। PerlIO::gzip
मॉड्यूल का उपयोग करके (के रूप में डेबियन में पैक libperlio-gzip-perl
) के बजाय IO::Uncompress::AnyUncompress
मुझे अपने 74MB लॉग फ़ाइलों को संसाधित करने के लिए लगभग 3.1 सेकंड का समय मिला । इसके बजाय एक साधारण हैश का उपयोग करके कुछ छोटे सुधार भी किए गए थे Set::Scalar
(जो IO::Uncompress::AnyUncompress
संस्करण के साथ कुछ सेकंड भी बचा था)।
PerlIO::gzip
में सबसे तेजी से पर्ल gunzip के रूप में सिफारिश की थी /programming//a/1539271/137158 (के लिए एक गूगल खोज के साथ पाया perl fast gzip decompress
)
इसके xargs -P
साथ प्रयोग करने से इसमें सुधार नहीं हुआ। वास्तव में यह 0.1 से 0.7 सेकंड तक कहीं भी इसे धीमा कर देता था। (मैंने चार रन की कोशिश की और मेरा सिस्टम पृष्ठभूमि में अन्य सामान करता है जो समय को बदल देगा)
मूल्य यह है कि स्क्रिप्ट का यह संस्करण केवल gzipped और असम्पीडित फ़ाइलों को संभाल सकता है। गति बनाम लचीलापन: इस संस्करण के लिए 3.1 सेकंड IO::Uncompress::AnyUncompress
एक xargs -P
आवरण (या बिना 1m13s xargs -P
) के साथ संस्करण के लिए 23 सेकंड बनाम ।
#! /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
पहले फाइलें।