即使脚本在以后多次执行,如何使部分代码在 perl “第一次执行时只运行一次”
问问题
1477 次
4 回答
2
您可以将那部分代码放在某个if
块中进行测试,例如使用文件,无论它是否是脚本的第一次执行,如果是,则仅执行该块。
于 2012-12-25T21:37:44.570 回答
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();
这只是一个概念;不幸的是,不能在这里测试它。但基本思想非常简单:在脚本中创建一个明确分隔的“运行一次”块,然后在第一次执行时,从脚本内容中删除该块。
于 2012-12-25T21:45:21.980 回答
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:~$
这是该问题的一个很好的可扩展解决方案,但 initialize 可能应该检查 is_initialized 本身,而不是期望主代码来执行它。
于 2012-12-25T22:18:58.860 回答
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 文件即可。
于 2012-12-26T08:41:57.807 回答