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

bar*_*ter 3 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

Rob*_*t P 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.
}
Run Code Online (Sandbox Code Playgroud)

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

sub cleanup { ... } # your cleanup code

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

END {
    cleanup();
}
Run Code Online (Sandbox Code Playgroud)

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


mob*_*mob 6

要回答如何END在任意时间调用块的狭隘问题,可以使用该B::end_av方法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");
Run Code Online (Sandbox Code Playgroud)

输出:

END BLOCK 2
END BLOCK 1
leave this program and never come back
Run Code Online (Sandbox Code Playgroud)

不过,我通常会喜欢不太神奇的东西.为什么不像一个结构

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

if (need_to_exec()) {
    cleanup();        # same thing END was going to do anyway
    exec( ... );
}
Run Code Online (Sandbox Code Playgroud)

?