在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
答案 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)
它会给你一个新的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块。
那就是说,我建议不要实现这种类型的进程级尾递归。