سؤال

أحيانا نسمع من يقول عن بيرل أنه قد يكون هناك 6 طرق مختلفة لمعالجة نفس المشكلة.جيد بيرل المطورين عادة ما يكون جيدا مسبب رؤى على اتخاذ الخيارات بين مختلف الأساليب الممكنة التنفيذ.

لذلك مثالا بيرل المشكلة:

سيناريو بسيط والتي تتكرر بشكل متكرر من خلال بنية الدليل ، وتبحث عن الملفات التي تم تعديلها مؤخرا (بعد تاريخ معين ، التي من شأنها أن تكون متغيرة).حفظ النتائج إلى ملف.

السؤال عن بيرل المطورين:ما هي أفضل طريقة لتحقيق هذا الهدف ؟

هل كانت مفيدة؟

المحلول

هذا يبدو وكأنه عمل. الملف::البحث::القاعدة:

#!/usr/bin/perl
use strict;
use warnings;
use autodie;  # Causes built-ins like open to succeed or die.
              # You can 'use Fatal qw(open)' if autodie is not installed.

use File::Find::Rule;
use Getopt::Std;

use constant SECONDS_IN_DAY => 24 * 60 * 60;

our %option = (
    m => 1,        # -m switch: days ago modified, defaults to 1
    o => undef,    # -o switch: output file, defaults to STDOUT
);

getopts('m:o:', \%option);

# If we haven't been given directories to search, default to the
# current working directory.

if (not @ARGV) {
    @ARGV = ( '.' );
}

print STDERR "Finding files changed in the last $option{m} day(s)\n";


# Convert our time in days into a timestamp in seconds from the epoch.
my $last_modified_timestamp = time() - SECONDS_IN_DAY * $option{m};

# Now find all the regular files, which have been modified in the last
# $option{m} days, looking in all the locations specified in
# @ARGV (our remaining command line arguments).

my @files = File::Find::Rule->file()
                            ->mtime(">= $last_modified_timestamp")
                            ->in(@ARGV);

# $out_fh will store the filehandle where we send the file list.
# It defaults to STDOUT.

my $out_fh = \*STDOUT;

if ($option{o}) {
    open($out_fh, '>', $option{o});
}

# Print our results.

print {$out_fh} join("\n", @files), "\n";

نصائح أخرى

حيث يتم حل المشكلة أساسا من المكتبات القياسية استخدامها.

الملف::نجد في هذه الحالة يعمل بشكل جيد.

قد يكون هناك العديد من الطرق أن تفعل أشياء في بيرل ، ولكن أين جدا المكتبة القياسية موجود القيام بشيء ما ، ينبغي أن تستخدم إلا إذا كان لديه مشاكل من نفسه.

#!/usr/bin/perl

use strict;
use File::Find();

File::Find::find( {wanted => \&wanted}, ".");

sub wanted {
  my (@stat);
  my ($time) = time();
  my ($days) = 5 * 60 * 60 * 24;

  @stat = stat($_);
  if (($time - $stat[9]) >= $days) {
    print "$_ \n";
  }
}

ليست هناك ست طرق للقيام بذلك, هناك الطريقة القديمة و طريقة جديدة.الطريقة القديمة مع الملف::تجد و أنت بالفعل بضعة أمثلة من ذلك.الملف::تجد لديه فظيعة جدا واجهة رد كان قبل 20 عاما, ولكن لقد انتقلت منذ ذلك الحين.

هنا الحياة الحقيقية (بخفة المعدلة) برنامج انا استخدم لمسح الغبار المتراكم تحت السرير على خوادم الإنتاج.فإنه يستخدم الملف::البحث::القاعدة بدلا من أن الملف::العثور على.الملف::البحث::قاعدة لطيفة التعريفي واجهة يقرأ بسهولة.

راندال شوارتز كما كتب الملف::الباحث ، كما المجمع أكثر من ملف::العثور على.انها لطيفة جدا لكنها لم تكن.

#! /usr/bin/perl -w

# delete temp files on agr1

use strict;
use File::Find::Rule;
use File::Path 'rmtree';

for my $file (

    File::Find::Rule->new
        ->mtime( '<' . days_ago(2) )
        ->name( qr/^CGItemp\d+$/ )
        ->file()
        ->in('/tmp'),

    File::Find::Rule->new
        ->mtime( '<' . days_ago(20) )
        ->name( qr/^listener-\d{4}-\d{2}-\d{2}-\d{4}.log$/ )
        ->file()
        ->maxdepth(1)
        ->in('/usr/oracle/ora81/network/log'),

    File::Find::Rule->new
        ->mtime( '<' . days_ago(10) )
        ->name( qr/^batch[_-]\d{8}-\d{4}\.run\.txt$/ )
        ->file()
        ->maxdepth(1)
        ->in('/var/log/req'),

    File::Find::Rule->new
        ->mtime( '<' . days_ago(20) )
        ->or(
            File::Find::Rule->name( qr/^remove-\d{8}-\d{6}\.txt$/ ),
            File::Find::Rule->name( qr/^insert-tp-\d{8}-\d{4}\.log$/ ),
        )
        ->file()
        ->maxdepth(1)
        ->in('/home/agdata/import/logs'),

    File::Find::Rule->new
        ->mtime( '<' . days_ago(90) )
        ->or(
            File::Find::Rule->name( qr/^\d{8}-\d{6}\.txt$/ ),
            File::Find::Rule->name( qr/^\d{8}-\d{4}\.report\.txt$/ ),
        )
        ->file()
        ->maxdepth(1)
        ->in('/home/agdata/redo/log'),

) {
    if (unlink $file) {
        print "ok $file\n";
    }
    else {
        print "fail $file: $!\n";
    }
}

{
    my $now;
    sub days_ago {
        # days as number of seconds
        $now ||= time;
        return $now - (86400 * shift);
    }
}

الملف::العثور على هو الطريق الصحيح لحل هذه المشكلة.لا يوجد أي استخدام في reimplementing الأشياء موجودة بالفعل في وحدات أخرى ، ولكن reimplementing شيء في الوحدة نمطية قياسية ينبغي أن يكون حقا بالإحباط.

ذكر آخرون الملف::البحث ، وهي الطريقة التي كنت اذهب, ولكن هل سألت عن التكرار ، والتي الملف::العثور على لا (ولا هو الملف::البحث::القاعدة).قد ترغب في النظر في الملف::التالي أو الملف::البحث::كائن, الذي لا يكون تكرارية الواجهات.مارك جاسون مولاي يذهب أكثر من بناء الخاصة بك في الفصل 4.2.2 من أعلى ترتيب Perl.

بلدي الأسلوب المفضل هو استخدام الملف::العثور على وحدة ذلك:

use File::Find;
find (\&checkFile, $directory_to_check_recursively);

sub checkFile()
{
   #examine each file in here. Filename is in $_ and you are chdired into it's directory
   #directory is also available in $File::Find::dir
}

هناك الملف::مكتشف, ، كما سبق ذكره ، ولكن هناك أيضا مكرر-as-a-تعادل-تجزئة الحل من العثور على الملفات تدريجيا (مجلة لينكس).

كتبت الملف::البحث::الإغلاق كما مجموعة من الإغلاقات التي يمكنك استخدامها مع::تجد لذلك لم يكن لديك لكتابة الخاصة بك.هناك بعض mtime الوظائف التي ينبغي التعامل معها

use File::Find;
use File::Find::Closures qw(:all);

my( $wanted, $list_reporter ) = find_by_modified_after( time - 86400 );
#my( $wanted, $list_reporter ) = find_by_modified_before( time - 86400 );

File::Find::find( $wanted, @directories );

my @modified = $list_reporter->();

أنت لا تحتاج إلى استخدام وحدة لأني في الغالب مصممة على أنها الطريقة التي يمكن أن ننظر إلى رمز وسرقة الأجزاء التي تريد.في هذه الحالة أنها أصعب قليلا لأن كل الوظائف الفرعية التي تتعامل مع القانون الأساسي يعتمد على روتين فرعي.عليك الحصول بسرعة على فكرة من رمز الرغم من ذلك.

حظا سعيدا ،

باستخدام الوحدات النمطية القياسية هو في الواقع فكرة جيدة ولكن من الاهتمام هنا هو العودة إلى النهج الأساسي باستخدام أي وحدات الخارجية.أنا أعرف رمز الجملة هنا قد لا يكون الجميع في كوب من الشاي.

فإنه يمكن تحسين استخدام ذاكرة أقل عبر توفير مكرر الوصول (المدخلات القائمة يمكن أن يكون مؤقتا على عقد بمجرد أن تصل إلى حجم معين) و تحقق المشروط يمكن توسيعها عن طريق الاستدعاء ref.

sub mfind {
    my %done;

    sub find {
        my $last_mod = shift;
        my $path = shift;

        #determine physical link if symlink
        $path = readlink($path) || $path;        

        #return if already processed
        return if $done{$path} > 1;

        #mark path as processed
        $done{$path}++;

        #DFS recursion 
        return grep{$_} @_
               ? ( find($last_mod, $path), find($last_mod, @_) ) 
                : -d $path
                   ? find($last_mod, glob("$path/*") )
                       : -f $path && (stat($path))[9] >= $last_mod 
                           ? $path : undef;
    }

    return find(@_);
}

print join "\n", mfind(time - 1 * 86400, "some path");

أنا أكتب روتين أن يقرأ مع الدليل readdir, يلقي بها على "." و ".." الدلائل ، recurses إذا وجد دليل جديد ، ويفحص الملفات ما أبحث عنه (في الحالة الخاصة بك ، سوف تحتاج إلى استخدام utime أو stat).قبل الوقت العودية يتم كل ملف يجب فحصها.

أعتقد أن كل الوظائف التي تحتاج لهذا السيناريو الموضحة هنا بإيجاز:http://www.cs.cf.ac.uk/Dave/PERL/node70.html

دلالات المدخلات والمخرجات هي تافهة إلى حد ما التمارين التي سوف أترك لكم.

أنا riskying للحصول على downvoted ، ولكن IMHO 'ls' (مع المناسبة params) الأمر أنها في أفضل المعروف performant الطريق.في هذه الحالة قد يكون من جيد جدا إلى حل الأنابيب 'ls' من كود بيرل من خلال شل تعود النتائج إلى مجموعة أو تجزئة.

تحرير:كما يمكن أن تكون 'العثور على' تستخدم على النحو المقترح في التعليقات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top