如何使代码的一部分在perl中只运行一次

时间:2012-12-25 21:33:39

标签: perl

如果代码的一部分只在perl中运行一次“第一次只执行”,即使脚本执行了很多次

4 个答案:

答案 0 :(得分:2)

您可以将代码中的那部分放在某个if块中,例如使用文件进行测试,无论是否是第一次执行脚本,如果是,只执行块。

答案 1 :(得分:2)

一种可行的方法是重写脚本本身,如下所示:

use warnings;
use script;

#### RUN ONCE BEGIN

do_something_once_only();

my $script_name = $0;
my $script_copy = $0 . 'old';
open my $fin, '<', $script_name or die $!;
open my $fout, '>', $script_copy or die $!;

my $script_content = do { local $/ = undef; <$fin>; };
$script_content =~ s/#### RUN ONCE BEGIN.+?#### RUN ONCE END/s;
print $fout $script_content;
`cp $script_copy $script_name`;

#### RUN ONCE END

do_something_else();

这只是一个概念;不幸的是,不能在这里测试它。但基本的想法很简单:你做了一个明确划定的“一次性运行”。在您的脚本中阻止,然后,在第一次执行时,从脚本的内容中删除此块。

答案 2 :(得分:1)

我会开发一个类对象,以非常清晰的英语来完成它的工作。在Ubuntu中,在/ var / run / [run_name] /下为脚本创建一个新目录,并在第一次运行时使用脚本在那里创建一个文件。例如:

文件名:RunOnce.pm

package RunOnce;
use Moose;

has 'run_name' => ( is => 'ro' , isa => 'Str' , required => 1 );
has 'initialize_file' => ( is => 'ro' , isa => 'Str'
    , builder => '_build_initialize_file'
    , lazy => 1 );

sub _build_initialize_file {
    return '/var/run/'. $_[0]->run_name . '/run_once.txt';
}

sub is_initialized {
    my $self = shift;
    return ( -f $self->initialize_file );
}

sub initialize {
    my $self = shift;
    open(my $init_file,'>' . $self->initialize_file )
         || die "Could not open initialize file "
            . $self->initialize_file . "! $!";
    $self->process_initial_run();
    print $init_file "Initialized on " . localtime(time) . "\n";
    close($init_file);
}

sub process_initial_run {
    warn "I don't do anything yet.";
}

package main;

my $runner = RunOnce->new(run_name => 'test_run');
$runner->initialize unless $runner->is_initialized();

1;

我刚在自己的盒子上测试过这个:

paul@paul-1204-virtualbox:~$ sudo rm -rf /var/run/test_run/
paul@paul-1204-virtualbox:~$ sudo mkdir /var/run/test_run/
paul@paul-1204-virtualbox:~$ sudo chown paul:paul /var/run/test_run
paul@paul-1204-virtualbox:~$ perl RunOnce.pm
I don't do anything yet. at RunOnce.pm line 29.
paul@paul-1204-virtualbox:~$ perl RunOnce.pm
paul@paul-1204-virtualbox:~$

现在你可以覆盖包和类并做你想做的事情,并且能够多次使用不同的项目,而不需要太多的工作:

新文件RunOnceOverride.pm:

package RunOnceOverride;

use Moose;

extends 'RunOnce';

sub process_initial_run {
    warn "I'm going to try to do something else!";
}

package main;

my $runner = RunOnceOverride->new(run_name => 'test_run_override');
$runner->initialize unless $runner->is_initialized();

1;

现在:

paul@paul-1204-virtualbox:~$ sudo rm -rf /var/run/test_run_override/
paul@paul-1204-virtualbox:~$ sudo mkdir /var/run/test_run_override/
paul@paul-1204-virtualbox:~$ sudo chown paul:paul /var/run/test_run_override/
paul@paul-1204-virtualbox:~$ perl -I. RunOnceOverride.pm
I'm going to try to do something else! at RunOnceOverride.pm line 8.
paul@paul-1204-virtualbox:~$ perl -I. RunOnceOverride.pm
paul@paul-1204-virtualbox:~$ 

这是一个很好的可扩展的问题解决方案,但是初始化应该检查is_initialized本身,而不是期望主代码执行它。

答案 3 :(得分:1)

你不能做这样的事情:

mySub if (!(-e "/some/path/cpuid.txt"));

sub mySub() {
    //do something
    open(my $cpuid, ">", "/some/path/cpuid.txt") || die $!;
    print $cpuid "blah";
}

顺便说一句,我不是任何形式的DRM的忠实粉丝。另外,你建议这样做的方式很容易打破。只需删除cpuid.txt文件就可以了。