ফাইলের যে কোনও জায়গায় একাধিক কীওয়ার্ডযুক্ত ফাইলগুলি সন্ধান করুন


16

আমি ফাইলের যে কোনও জায়গায় যে সন্ধানের কীওয়ার্ডগুলির পুরো সেট ধারণ করে এমন একটি ডিরেক্টরিতে সমস্ত ফাইল তালিকাভুক্ত করার উপায় খুঁজছি।

সুতরাং, কীওয়ার্ডগুলির একই লাইনে উপস্থিত হওয়ার দরকার নেই।

এটি করার একটি উপায় হ'ল:

grep -l one $(grep -l two $(grep -l three *))

তিনটি কীওয়ার্ড কেবল একটি উদাহরণ, এটি পাশাপাশি দুটি, বা চার এবং আরও অনেক কিছু হতে পারে।

দ্বিতীয় উপায়টি আমি ভাবতে পারি:

grep -l one * | xargs grep -l two | xargs grep -l three

তৃতীয় পদ্ধতি, যা অন্য প্রশ্নের মধ্যে হাজির হয়েছিল, তা হ'ল :

find . -type f \
  -exec grep -q one {} \; -a \
  -exec grep -q two {} \; -a \
  -exec grep -q three {} \; -a -print

তবে আমি এখানে যে দিকনির্দেশনা দিচ্ছি তা অবশ্যই তা নয় । আমি এমন কিছু বিষয় যা অপেক্ষাকৃত কম টাইপ প্রয়োজন, এবং সম্ভবত শুধু একটা কল চান grep, awk, perlবা অনুরূপ।

উদাহরণস্বরূপ, আমি পছন্দ করি যে কীভাবে awkআপনাকে সমস্ত কীওয়ার্ড যুক্ত রেখাগুলি মেলে দেয় :

awk '/one/ && /two/ && /three/' *

অথবা, কেবল ফাইলের নামগুলি মুদ্রণ করুন:

awk '/one/ && /two/ && /three/ { print FILENAME ; nextfile }' *

তবে আমি এমন ফাইলগুলি খুঁজতে চাইছি যেখানে কীওয়ার্ডগুলি ফাইলের যে কোনও জায়গায় থাকতে পারে, একই লাইনে অগত্যা নয়।


পছন্দসই সমাধানগুলি জিজপ বান্ধব হবে, উদাহরণস্বরূপ সংক্রামিত ফাইলগুলিতে কাজ করে এমন বৈকল্পিক grepরয়েছে zgrep। আমি কেন এটি উল্লেখ করি, তা হ'ল এই সীমাবদ্ধতার কারণে কিছু সমাধান ভালভাবে কাজ করতে পারে না। উদাহরণস্বরূপ, awkমিলে যাওয়া ফাইলগুলি মুদ্রণের উদাহরণে আপনি কেবল এটি করতে পারবেন না:

zcat * | awk '/pattern/ {print FILENAME; nextfile}'

আপনাকে কমান্ডটি উল্লেখযোগ্যভাবে পরিবর্তন করতে হবে যেমন:

for f in *; do zcat $f | awk -v F=$f '/pattern/ { print F; nextfile }'; done

সুতরাং, সীমাবদ্ধতার কারণে, আপনাকে awkঅনেকবার কল করা দরকার , যদিও আপনি কেবল একবার সঙ্কুচিত ফাইল দিয়েই করতে পারেন। এবং অবশ্যই, ঠিক কাজটি করা zawk '/pattern/ {print FILENAME; nextfile}' *এবং একই প্রভাব পাওয়া ভাল লাগবে, তাই আমি সমাধানগুলি পছন্দ করি যা এটির অনুমতি দেয়।


1
আপনার gzipবন্ধুত্বপূর্ণ হওয়ার দরকার নেই , কেবল zcatআগে ফাইলগুলি।
টেরডন

@ স্টারডন আমি পোস্টটি সম্পাদনা করেছি, কেন আমি উল্লেখ করি যে ফাইলগুলি সংকুচিত করা হয়েছে।
arekolek

একবার বা অনেকবার অ্যাডাব্লিক চালু করার মধ্যে খুব বেশি পার্থক্য নেই। আমি বলতে চাইছি, ঠিক আছে, কিছু ছোট ওভারহেড কিন্তু আমি সন্দেহ করি যে আপনি এমনকি পার্থক্যটি লক্ষ্য করবেন। অবশ্যই স্ক্রিপ্টটি নিজেই যা-ই করুক / পার্ল তৈরি করা সম্ভব তবে এটি একটি দ্রুত বর্ধিত প্রোগ্রাম হতে শুরু করে এবং দ্রুত ওয়ান-লাইনার নয়। তুমি কি এটাই চাও?
টেরডন

@ অ্যারডন ব্যক্তিগতভাবে, আমার কাছে আরও গুরুত্বপূর্ণ দিকটি হ'ল আদেশটি কতটা জটিল হবে (আমার ধারণা আপনি মন্তব্য করার সময় আমার দ্বিতীয় সম্পাদনাটি এসেছিল)। উদাহরণস্বরূপ, grepসমাধানগুলি কেবলমাত্র একটির grepসাথে উপসর্গের মাধ্যমে সহজেই মানিয়ে যায় z, ফাইলের নামগুলিও হ্যান্ডেল করার দরকার নেই।
arekolek

হ্যাঁ, কিন্তু এর যে grep। আফাইক, কেবল grepএবং catমানক "জেড-ভেরিয়েন্টস" রয়েছে। আমি মনে করি না আপনি কোনও for f in *; do zcat -f $f ...সমাধান ব্যবহারের চেয়ে সহজ কিছু পাবেন । অন্য যে কোনও কিছুতে এমন একটি সম্পূর্ণ প্রোগ্রাম হতে হবে যা খোলার আগে ফাইল ফর্ম্যাটগুলি পরীক্ষা করে বা এটি করার জন্য একটি লাইব্রেরি ব্যবহার করে।
টেরডন

উত্তর:


13
awk 'FNR == 1 { f1=f2=f3=0; };

     /one/   { f1++ };
     /two/   { f2++ };
     /three/ { f3++ };

     f1 && f2 && f3 {
       print FILENAME;
       nextfile;
     }' *

আপনি যদি জিজেপ করা ফাইলগুলি স্বয়ংক্রিয়ভাবে পরিচালনা করতে চান তবে হয় এটির সাহায্যে একটি লুপটিতে চালান 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এখানে ... সেগুলিতে পরীক্ষার জন্য "এক" "দুটি" "তিন" "চার" "পাঁচ" এবং "ছয়" শব্দগুলির কিছু বা সমস্ত কিছু রয়েছে contain উপরের আউটপুটে তালিকাভুক্ত ফাইলগুলি তিনটি অনুসন্ধান নিদর্শন রয়েছে DO এটি নিজের নিজের ডেটা দিয়ে নিজেই পরীক্ষা করুন)

#! /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)), ফাইলের নামটি মুদ্রণ করুন এবং পরবর্তী ফাইলটিতে যান ip

এটি বিশেষত দ্রুত সমাধান নয়, তবে অযৌক্তিকভাবে ধীর নয়। প্রথম সংস্করণটি 4 এম 58 সেকেন্ডে 74 এমবি মূল্যের সংকুচিত লগ ফাইলগুলিতে তিনটি শব্দ অনুসন্ধান করতে (মোট 937 এমবি সঙ্কুচিত) search এই বর্তমান সংস্করণটি 1m13s সময় নেয়। সম্ভবত আরও আশাবাদীগুলি তৈরি করা যেতে পারে।

একটি সুস্পষ্ট অপ্টিমাইজেশন হ'ল এটি সমান্তরালভাবে ফাইলের সাবসেটে একাধিক অনুসন্ধান চালানোর জন্য xargsএর -Pওরফে সাথে ব্যবহার করে --max-procs। এটি করার জন্য, আপনাকে ফাইলের সংখ্যা গণনা করতে হবে এবং আপনার সিস্টেমের কর / সিপাস / থ্রেডের সংখ্যা দ্বারা বিভক্ত করতে হবে (এবং 1 যোগ করে গোল করবে)। যেমন আমার নমুনা সেটে 269 টি ফাইল অনুসন্ধান করা হয়েছিল এবং আমার সিস্টেমে 6 টি কর (একটি এএমডি 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 সেকেন্ডের মধ্যে তাদের সমস্ত (269 ফাইলের 74MB নমুনায়) মাধ্যমে চলে। এটি যদি কিছু ক্ষেত্রে কার্যকর হয় -l 100তবে এটি একটি কমান্ড লাইন বিকল্প হিসাবে তৈরি করা যেতে পারে (উদাঃ ) তবে এর সাথে সমস্ত মিলে যাওয়া ফাইলগুলি খুঁজে না পাওয়ার ঝুঁকি রয়েছে ।


বিটিডব্লিউ, এর জন্য ম্যান পেজ অনুসারে, সংক্ষিপ্ত রূপগুলি IO::Uncompress::AnyUncompressসমর্থিত:


একটি শেষ (আমি আশা করি) অপ্টিমাইজেশন। ব্যবহারের PerlIO::gzipমডিউল (যেমন ডেবিয়ান প্যাকেজ libperlio-gzip-perl) পরিবর্তে IO::Uncompress::AnyUncompressআমি সম্পর্কে নিচে সময় পেয়েছিলাম 3.1 সেকেন্ড লগ ফাইল আমার 74MB প্রক্রিয়াকরণের জন্য। পরিবর্তে একটি সাধারণ হ্যাশ ব্যবহার করে কিছু ছোট উন্নতি হয়েছে Set::Scalar(যা IO::Uncompress::AnyUncompressসংস্করণটির সাথে কয়েক সেকেন্ডও সাশ্রয় করেছে)।

PerlIO::gzip/programming//a/1539271/137158 (যার জন্য গুগল অনুসন্ধানের সাথে পাওয়া গেছে 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;
    }
  }
}

for f in *; do zcat $f | awk -v F=$f '/one/ {a++}; /two/ {b++}; /three/ {c++}; a&&b&&c { print F; nextfile }'; doneসূক্ষ্মভাবে কাজ করে, তবে প্রকৃতপক্ষে, আমার grepসমাধান হিসাবে 3 গুণ সময় সময় নেয় এবং এটি আসলে আরও জটিল।
arekolek

1
OTOH, সরল পাঠ্য ফাইলগুলির জন্য এটি দ্রুত হবে। এবং একই অ্যালগরিদম সংক্ষেপিত ফাইলগুলি (পার্ল বা পাইথনের মতো) পড়ার পক্ষে সমর্থন করে একটি ভাষায় প্রয়োগ করা হয়েছিল যেমনটি আমি প্রস্তাব করেছি যে একাধিক গ্রেপের চেয়ে দ্রুত হবে। "জটিলতা" আংশিকভাবে বিষয়গত - ব্যক্তিগতভাবে, আমি মনে করি যে একক অজক বা পারল বা পাইথন স্ক্রিপ্টটি একাধিক গ্রেপের চেয়ে কম জটিল বা পাওয়া ছাড়া পাওয়া যায় .... @ টেরডনের উত্তর ভাল, এবং আমি যে মডিউলটির উল্লেখ করেছি তার প্রয়োজন ছাড়াই এটি করে (তবে প্রত্যেক compresssed ফাইলের জন্য zcat forking) এর খরচে
সি এ এস

আমাকে apt-get install libset-scalar-perlস্ক্রিপ্ট ব্যবহার করতে হয়েছিল। তবে এটি কোনও যুক্তিসঙ্গত সময়ে শেষ হবে বলে মনে হয় না।
arekolek

আপনি যে ফাইলগুলি অনুসন্ধান করছেন তা কতগুলি এবং কোন আকার (সংকুচিত এবং সঙ্কুচিত) রয়েছে? কয়েক ডজন বা মাঝারি আকারের কয়েকশ ফাইল বা হাজার হাজার বড়?
কাস

সংক্ষিপ্ত ফাইলগুলির আকারের একটি হিস্টগ্রাম এখানে রয়েছে (20 থেকে 100 ফাইল, 50MB অবধি তবে বেশিরভাগ 5MB এর নীচে)। সঙ্কোচিত দেখতে একই, তবে মাপগুলি 10 দ্বারা গুণিত হয়েছে
arekolek

11

রেকর্ড পৃথককারীকে সেট করুন .যাতে awkপুরো ফাইলটিকে এক লাইনের মতো দেখাবে:

awk -v RS='.' '/one/&&/two/&&/three/{print FILENAME}' *

একইভাবে perl:

perl -ln00e '/one/&&/two/&&/three/ && print $ARGV' *

3
ঝরঝরে। মনে রাখবেন যে এটি পুরো ফাইলটিকে মেমরিতে লোড করবে এবং এটি বড় ফাইলগুলির জন্য সমস্যা হতে পারে।
টেরডন

আমি প্রথম দিকে এটি উন্নত করেছিলাম, কারণ এটি আশাব্যঞ্জক বলে মনে হয়েছিল। তবে আমি এটি জিপিড ফাইলগুলির সাথে কাজ করতে পারি না। for f in *; do zcat $f | awk -v RS='.' -v F=$f '/one/ && /two/ && /three/ { print F }'; doneকিছুই আউটপুট।
arekolek

@arekolek এই লুপটি আমার পক্ষে কাজ করে। আপনার ফাইলগুলি সঠিকভাবে জিপ করা হয়েছে?
জিম্মিজ

@arekolek আপনার zcat -f "$f"কিছু ফাইল সংকুচিত না হলে প্রয়োজন ।
টেরডন

আমি এটি অসম্পূর্ণ ফাইলগুলিতেও পরীক্ষা করেছি এবং awk -v RS='.' '/bfs/&&/none/&&/rgg/{print FILENAME}' greptest/*.txtএখনও grep -l rgg $(grep -l none $(grep -l bfs greptest/*.txt))প্রত্যাশিত ফলাফল প্রত্যাবর্তন করার পরে কোনও ফল দেয় না ।
arekolek

3

সংকুচিত ফাইলগুলির জন্য, আপনি প্রতিটি ফাইলের উপর লুপ করতে পারেন এবং প্রথমে ডিকম্প্রেস করতে পারেন। তারপরে, অন্যান্য উত্তরের কিছুটা পরিবর্তিত সংস্করণ দিয়ে আপনি এটি করতে পারেন:

for f in *; do 
    zcat -f "$f" | perl -ln00e '/one/&&/two/&&/three/ && exit(0); }{ exit(1)' && 
        printf '%s\n' "$f"
done

পার্ল স্ক্রিপ্টটি 0তিনটি স্ট্রিং পাওয়া গেলে স্থিতি (সাফল্য) দিয়ে প্রস্থান করবে । }{জন্য পার্ল সাধারণভাবে সংক্ষেপে হয় END{}। সমস্ত ইনপুট প্রক্রিয়া করার পরে এটি অনুসরণ করা যে কোনও কিছুই কার্যকর করা হবে। সুতরাং সমস্ত স্ট্রিং না পাওয়া গেলে স্ক্রিপ্টটি অ -0 প্রস্থান স্থিতি দিয়ে প্রস্থান করবে। সুতরাং, && printf '%s\n' "$f"তিনটিই পাওয়া গেলে কেবল ফাইলটি ফাইলের নাম মুদ্রণ করবে।

বা, মেমোরিতে ফাইল লোড করা এড়াতে:

for f in *; do 
    zcat -f "$f" 2>/dev/null | 
        perl -lne '$k++ if /one/; $l++ if /two/; $m++ if /three/;  
                   exit(0) if $k && $l && $m; }{ exit(1)' && 
    printf '%s\n' "$f"
done

অবশেষে, আপনি যদি সত্যিই কোনও স্ক্রিপ্টে পুরো কাজটি করতে চান তবে আপনি এটি করতে পারেন:

#!/usr/bin/env perl

use strict;
use warnings;

## Get the target strings and file names. The first three
## arguments are assumed to be the strings, the rest are
## taken as target files.
my ($str1, $str2, $str3, @files) = @ARGV;

FILE:foreach my $file (@files) {
    my $fh;
    my ($k,$l,$m)=(0,0,0);
    ## only process regular files
    next unless -f $file ;
    ## Open the file in the right mode
    $file=~/.gz$/ ? open($fh,"-|", "zcat $file") : open($fh, $file);
    ## Read through each line
    while (<$fh>) {
        $k++ if /$str1/;
        $l++ if /$str2/;
        $m++ if /$str3/;
        ## If all 3 have been found
        if ($k && $l && $m){
            ## Print the file name
            print "$file\n";
            ## Move to the net file
            next FILE;
        }
    }
    close($fh);
}

উপরের স্ক্রিপ্টটি foo.plআপনার অন্য কোথাও সংরক্ষণ করুন $PATH, এটাকে এক্সিকিউটেবল করুন এবং এটিকে এভাবে চালান:

foo.pl one two three *

2

এখনও অবধি প্রস্তাবিত সমস্ত সমাধানগুলির মধ্যে, গ্রেপ ব্যবহার করে আমার মূল সমাধানটি দ্রুততম, 25 সেকেন্ডে সমাপ্ত। এটির ব্যর্থতা হ'ল কীওয়ার্ডগুলি যুক্ত করতে এবং অপসারণ করা ক্লান্তিকর। সুতরাং আমি এমন একটি স্ক্রিপ্ট নিয়ে এসেছি (ডাব করা multi) যা আচরণটি অনুকরণ করে তবে সিনট্যাক্সটি পরিবর্তন করতে দেয়:

#!/bin/bash

# Usage: multi [z]grep PATTERNS -- FILES

command=$1

# first two arguments constitute the first command
command_head="$1 -le '$2'"
shift 2

# arguments before double-dash are keywords to be piped with xargs
while (("$#")) && [ "$1" != -- ] ; do
  command_tail+="| xargs $command -le '$1' "
  shift
done
shift

# remaining arguments are files
eval "$command_head $@ $command_tail"

সুতরাং, এখন লেখাটি multi grep one two three -- *আমার মূল প্রস্তাবের সমান এবং একই সময়ে চলে runs আমি এটির zgrepপরিবর্তে প্রথম যুক্তি হিসাবে সহজেই সংক্ষেপিত ফাইলগুলিতে ব্যবহার করতে পারি ।

অন্যান্য সমাধান

আমি দুটি কৌশল ব্যবহার করে পাইথন স্ক্রিপ্টটিও পরীক্ষা করে দেখেছি: প্রতিটি কীওয়ার্ড লাইন দ্বারা লাইন অনুসন্ধান করা এবং কীওয়ার্ডের সাহায্যে পুরো ফাইল কীওয়ার্ড অনুসন্ধান করে। দ্বিতীয় কৌশলটি আমার ক্ষেত্রে দ্রুত ছিল। তবে এটি কেবল ব্যবহারের চেয়ে ধীর ছিল 33৩ grepসেকেন্ডে শেষ। লাইন বাই লাইন কীওয়ার্ডের মিলটি 60 সেকেন্ডে শেষ হয়েছে।

#!/usr/bin/python3

import gzip, sys

i = sys.argv.index('--')
patterns = sys.argv[1:i]
files = sys.argv[i+1:]

for f in files:
  with (gzip.open if f.endswith('.gz') else open)(f, 'rt') as s:
    txt = s.read()
    if all(p in txt for p in patterns):
      print(f)

স্ক্রিপ্ট terdon কর্তৃক প্রদত্ত 54 সেকেন্ডের মধ্যে সমাপ্ত। প্রকৃতপক্ষে এটি 39 সেকেন্ড সময় লাগল প্রাচীরের সময়, কারণ আমার প্রসেসর দ্বৈত কোর যা আকর্ষণীয়, কারণ আমার পাইথন স্ক্রিপ্টটি 49 সেকেন্ড ওয়াল সময় নিয়েছিল (এবং এটি grepছিল 29 সেকেন্ড)।

ক্যাস দ্বারা স্ক্রিপ্টটি যুক্তিসঙ্গত সময়ে শেষ করতে ব্যর্থ হয়েছিল, এমনকি grep4 সেকেন্ডের নীচে প্রসেস হওয়া অল্প সংখ্যক ফাইলগুলিতেও , আমাকে এটি মেরে ফেলতে হয়েছিল।

তবে তার আসল awkপ্রস্তাবটি যদিও তার চেয়ে ধীর গতিতে রয়েছে grep, এর সম্ভাব্য সুবিধা রয়েছে। কিছু ক্ষেত্রে, কমপক্ষে আমার অভিজ্ঞতায়, আশা করা যায় যে সমস্ত কীওয়ার্ডগুলি ফাইলের একেবারে যদি ফাইলের মধ্যে থাকে তবে সেগুলি ফাইলের মাথায় কোথাও উপস্থিত হওয়া উচিত। এটি এই সমাধানটিকে কার্য সম্পাদনে নাটকীয় উত্সাহ দেয়:

for f in *; do
  zcat $f | awk -v F=$f \
    'NR>100 {exit} /one/ {a++} /two/ {b++} /three/ {c++} a&&b&&c {print F; exit}'
done

25 সেকেন্ডের বিপরীতে, এক সেকেন্ডের এক চতুর্থাংশে শেষ।

অবশ্যই, ফাইলগুলির শুরুতে আমাদের কাছে কীওয়ার্ডগুলির সন্ধানের সুবিধার নাও থাকতে পারে। এই ক্ষেত্রে, সমাধান ছাড়াই NR>100 {exit}seconds৩ সেকেন্ড (প্রাচীরের সময়কাল 50s) লাগে।

অসম্পূর্ণ ফাইল

আমার grepসমাধান এবং ক্যাসের awkপ্রস্তাবের মধ্যে চলমান সময়টিতে কোনও তাত্পর্যপূর্ণ পার্থক্য নেই , উভয়ই সম্পাদন করতে এক সেকেন্ডের ভগ্নাংশ গ্রহণ করে।

নোট করুন যে চলক প্রারম্ভিককরণটি FNR == 1 { f1=f2=f3=0; }পরবর্তী প্রতিটি প্রক্রিয়াজাত ফাইলের জন্য কাউন্টারগুলি পুনরায় সেট করতে এই জাতীয় ক্ষেত্রে বাধ্যতামূলক। এর মতো, আপনি যদি কোনও কীওয়ার্ড পরিবর্তন করতে চান বা একটি নতুন যুক্ত করতে চান তবে এই সমাধানটির জন্য তিন জায়গায় কমান্ড সম্পাদনা করা দরকার। অন্যদিকে, grepআপনি নিজের পছন্দমতো | xargs grep -l fourকীওয়ার্ড যুক্ত করতে বা সম্পাদনা করতে পারবেন ।

grepকমান্ড সাবস্টিটিউশন ব্যবহার করে এমন সমাধানের একটি অসুবিধা হ'ল এটি স্তব্ধ হয়ে যাবে যদি চেইনের যে কোনও জায়গায়, শেষ ধাপের আগে, কোনও মেলানো ফাইল নেই। এটি xargsবৈকল্পিকটিকে প্রভাবিত করে না কারণ পাইপটি একবার grepশূন্য-স্থিতি স্থিতি ফিরিয়ে দেওয়া হবে । আমি আমার স্ক্রিপ্টটি ব্যবহার করার জন্য আপডেট করেছি xargsযাতে আমাকে এটি নিজেই পরিচালনা করতে হবে না, স্ক্রিপ্টটিকে সহজ করে তুলতে।


আপনার পাইথন not all(p in text for p in patterns)
দ্রবণটি লুপটিকে

@iruvar পরামর্শের জন্য ধন্যবাদ। আমি এটি চেষ্টা করেছি (সানস not) এবং এটি 32 সেকেন্ডের মধ্যে শেষ হয়েছে, এত উন্নতি হয়নি, তবে এটি অবশ্যই আরও পাঠযোগ্য।
arekolek

আপনাকে-প্যাটার্ন বরং F1, F2, awk মধ্যে F3 চেয়ে একটি মিশুক অ্যারে ব্যবহার করতে পারে, কী দিয়ে =, Val = গণনা
CA গুলির

@arekolek PerlIO::gzipপরিবর্তে আমার সর্বশেষতম সংস্করণটি দেখুন IO::Uncompress::AnyUncompress। আমার M৪ এমবি লগ ফাইলগুলি প্রক্রিয়া করতে এখন 1 মি 13 এর পরিবর্তে মাত্র 3.1 সেকেন্ড সময় নেয়।
কাস

বিটিডাব্লু, আপনি যদি আগে চালিত হয়ে থাকেন eval $(lesspipe)(যেমন আপনার .profile, ইত্যাদি), আপনি এর lessপরিবর্তে ব্যবহার করতে পারেন zcat -fএবং আপনার forলুপের মোড়ক দেওয়া awkকোনও প্রকারের ফাইল less(gzip, bzip2, xz, এবং আরও) প্রসেস করতে সক্ষম হবে .... stdout একটি পাইপ কিনা তা কম সনাক্ত করতে পারে এবং স্টডআউট হলে কেবল স্ট্রিম আউটপুট দেবে will
ক্যাস

0

অন্য বিকল্প - ফাইলের বিরুদ্ধে xargsচালানোর জন্য শব্দটিকে একবারে ফিড grepকরুন। xargsএটির কাছে grepফিরে আসার 255সাথে সাথে ব্যর্থতার অনুরোধের সাথে সাথেই প্রস্থান করার জন্য তৈরি করা যেতে পারে ( xargsডকুমেন্টেশন চেক করুন )। অবশ্যই শাঁসগুলির স্পোং এবং এই দ্রবণটির সাথে জড়িত থাকা সম্ভবত এটি উল্লেখযোগ্যভাবে কমিয়ে দেবে

printf '%s\n' one two three | xargs -n 1 sh -c 'grep -q $2 $1 || exit 255' _ file

এবং এটি লুপ আপ

for f in *; do
    if printf '%s\n' one two three | xargs -n 1 sh -c 'grep -q $2 $1 || exit 255' _ "$f"
    then
         printf '%s\n' "$f"
    fi
done

এটি দেখতে দুর্দান্ত লাগছে তবে আমি কীভাবে এটি ব্যবহার করব তা নিশ্চিত নই। কি _এবং file? একাধিক ফাইলে এই সন্ধানটি কী কীওয়ার্ড যুক্ত যুক্তি এবং ফিরিয়ে দেবে?
arekolek

@arekolek, একটি লুপ সংস্করণ যুক্ত করুন। এবং হিসাবে _, এটি $0তৈরি শেলটি হিসাবে প্রেরণ করা হচ্ছে - এটি আউটপুটে কমান্ডের নাম হিসাবে প্রদর্শিত psহবে - আমি এখানে মাস্টারের কাছে স্থগিত করব
Iruvar
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.