我正在尝试使用Perl Parallel:ForkManager运行多个命令。我希望这些命令在不同的时间段运行。我正在使用子程序is_time_elapsed来检查是否是运行命令的时间。如果子例程返回0,那么我正在使用并行fork管理器运行该命令。命令正在执行,但我在屏幕上看到STDOUT。相反,我想将STDOUT和STDERR重定向到一个文件。如何防止STDOUT在屏幕上看到并重定向到文件
我的要求是在时间结束后在后台运行命令。我需要在命令完成执行时记录执行时间。该脚本将是一个主脚本,它将无限运行并在时间结束后运行命令。除了Parallel :: ForkManager之外,还有其他任何模块可以实现这一目标。
my $forkMgr = Parallel::ForkManager->new(15);
$forkMgr->run_on_finish(
sub {
($pid, $exitCode, $ident) = @_;
print "Ended ==> $ident\n";
}
);
while (1) {
foreach my $cmd (@commands) {
if (is_time_elapsed($cmd)) {
$forkMgr->start($cmd)
and next;
exec("$cmd")
or die("exec: $!");
$forkMgr->finish;
}
}
sleep 30
}
答案 0 :(得分:3)
重定向整个程序及其子程序的所有输出:
main_program >log 2>&1
仅重定向子项的输出:
if (is_time_elapsed($cmd)) {
$forkMgr->start($cmd)
and next;
open(STDOUT, '>>', 'log')
or die("open: $!");
open(STDERR, '>>&', \*STDOUT)
or die("open: $!");
exec("$cmd")
or die("exec: $!");
}
如果您愿意,您甚至可以将每个孩子的输出重定向到另一个文件。
注意:我摆脱了$forkMgr->finish
。从来没有达到过(这很好)。
答案 1 :(得分:2)
与Perl一样,有几种方法可以实现这一点。您还没有说明要将哪些输出发送到文件,或者根本不需要真正的STDOUT
。让我们探讨一下您的选择。
STDOUT
如果您的主程序以及所有工作人员永远不应该向STDOUT
打印任何内容,您可以使用输出重定向来运行它。这使您可以在开发期间对STDOUT
进行调试,并在生产中写入文件。
只需使用附加到命令的>output.log
启动程序即可。所有分叉的输出也将转到该文件。 STDERR
将保持不变。
$ perl forker.pl >output.log
如果您希望所有输出都转到文件,这应该是首选方法。
或者,您可以在Perl中实现此功能。这会让你失去在控制台上调试的能力,你总是要看文件。使用select
更改print
的默认句柄。请务必使用append-mode >>
作为新句柄。
open my $fh, '>>', 'output.log' or die $!;
select $fh;
my $forkMgr = Parallel::FormManager->new(15);
# ...
现在所有输出也将转到该文件。 See this blog post了解有关其工作原理的详细信息,以及如何恢复原始STDOUT
。
STDOUT
Capture::Tiny非常适合抓住STDOUT
的东西。您可以使用它来包装exec
。
use Capture::Tiny 'capture_stdout';
# ...
my $stdout = capture_stdout {
exec($cmd);
}
现在您可以将其写入文件。
Log::Log4Perl是高级日志记录的首选模块。您应该能够告诉它不仅从STDERR
获取所有内容,还从STDOUT
获取所有内容。我没有研究过这个,但它应该有用。