强制Perl在以exec()结尾时调用END子例程?

时间:2012-01-31 16:50:50

标签: perl

在Perl中使用exec()

  

请注意,exec不会调用您的END块,也不会在您的对象上调用DESTROY方法。

如何强制perl呼叫END阻止?我可以做END(); exec($0)或其他什么吗?

我真的想让程序结束它的当前实例并启动一个全新的实例,并且我懒得正确地执行此操作(使用cron或将整个程序置于无限循环中)。但是,我的END子程序清理临时文件和其他重要的东西,所以我需要它们在执行之间运行。

无益的代码链接:

https://github.com/barrycarter/bcapps/blob/master/bc-metar-db.pl

https://github.com/barrycarter/bcapps/blob/master/bc-voronoi-temperature.pl

https://github.com/barrycarter/bcapps/blob/master/bc-delaunay-temperature.pl

4 个答案:

答案 0 :(得分:10)

所以你试图在你的脚本中执行一个程序? exec可能不是你想要的。 exec的行为类似于C exec:所谓的替换您当前的流程;为了继续前进,您必须执行fork之类的操作来保留当前进程,同时执行另一个进程。

但好消息!这一切都存在于system内置。

  

与exec LIST完全相同,除了首先完成fork并且父进程等待子进程退出。

这是它的样子:

use 5.012; # or use 5.012 or newer
use warnings;

... # some part of my program

system($my_command, $arg1, $arg2); # forks, execs, returns.

END {
    # still gets called because you never left the script.
}

如果您绝对必须使用exec,则必须自动调用清理例程。要了解有关END的更多信息,请参阅perldoc perlmod了解详细信息。缺点:END是在脚本执行的特定阶段执行的几种代码块之一。它们不是子程序。但是,您可以在这些子例程中执行您想要的任何代码。所以你可以这样做:

sub cleanup { ... } # your cleanup code

sub do_exec {
    cleanup();
    exec( ... );
}

END {
    cleanup();
}

然后你知道你的清理代码将在任何一个脚本出口或执行你的exec时执行。

答案 1 :(得分:6)

要回答如何在任意时间调用END块的狭隘问题,您可以使用B::SV::object_2svref方法和END来获取sub invoke_end_blocks_before_exec { use B; my @ENDS = B::end_av->ARRAY; foreach my $END (@ENDS) { $END->object_2svref->(); } } END { print "END BLOCK 1\n" } END { print "END BLOCK 2\n" } ... invoke_end_blocks_before_exec(); exec("echo leave this program and never come back"); 的代码引用块。

END BLOCK 2
END BLOCK 1
leave this program and never come back

输出:

sub cleanup { ... }
END { &cleanup }

if (need_to_exec()) {
    cleanup();        # same thing END was going to do anyway
    exec( ... );
}
但是,我通常会喜欢不太神奇的东西。为什么不像

这样的结构
{{1}}

答案 2 :(得分:4)

Fork和exec

它会给你一个新的pid,但你可以fork / exec

my $pid = fork();
defined $pid or die "fork failed";
exit if $pid; # parent immediately exits, calling END blocks.
exec($0) or die "exec failed"; # child immediately execs, will not call END blocks (but parent did, so OK)

这让我感到非常脆弱,而不是与内部人员混淆或试图确保你的执行官在最后的END区块。

包装你的程序

此外,只需将您的Perl程序包装在shell(或Perl)脚本中,它就是琐碎,如下所示:

#!/bin/sh

while sleep 5m; do
    perl your-program.pl
done

#!/usr/bin/perl

while (1) {
    system("perl your-program.pl");
    sleep(5*60);
}

答案 3 :(得分:2)

您可以在(最终)exec阻止结束时将您的电话转到END吗?您当前拨打exec的地方,设置一个标志,然后exit。在END块的末尾,检查标志,如果是,则在那里调用exec。这样,您可以在不重新启动的情况下退出脚本,如果需要,仍然可以执行END块。

那就是说,我建议不要实现这种类型的进程级尾递归。