如何同时使用Parallel::ForkManager和Capture::Tiny?

3
以下是我问题的简化示例。在这里,exec应该会报错,因为xecho不存在。
问题
有没有办法让Capture::Tiny捕获Parallel::ForkManager的输出?
#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;
use Capture::Tiny 'capture';

my ($stdout, $stderr, $exit) = capture {
    my $pm = Parallel::ForkManager->new(5);
    my $pid = $pm->start;
    if (!$pid) {
        no warnings;  # no warnings "exec" is not working
        exec("xecho test");
        $pm->finish;
    }
};

print "$stdout\n";
print "$exit\n";
print "$stderr\n";

什么是xecho?我怀疑它绕过了捕获,而Parallel::ForkManager与你的问题无关。 - ysth
@ysth 这只是一个不存在的命令,用于模拟错误。 - Jasmine Lognnes
但除了执行失败的警告之外,没有任何输出;你想要捕获什么? - ysth
1
我认为你应该将一些内容还原并展示更接近实际情况的东西。例如,你不需要等待子进程完成。 - ysth
@ysth 是的,问题在于我使用 parallel::ForkManager 时没有任何输出。如果将其删除,则会在 $stderr 中输出 file not found,这正是我想要的。我的确切情况是启动 ssh 来执行远程命令。我以为我正在等待子进程完成。但如果我没有等待,那么它就可以解释我另一个问题 =)如何让它等待子进程完成? - Jasmine Lognnes
1个回答

1

您无法使用 Capture::Tiny 来捕获子进程的输出,但是您可以使用 Parallel::ForkManagerrun_on_finish 方法:

use strict;
use warnings;

use Capture::Tiny qw(capture);
use Data::Dump;
use Parallel::ForkManager;

my $pm = Parallel::ForkManager->new(5);
$pm -> run_on_finish (
  sub {
    my (
        $pid, $exit_code, $ident, $exit_signal, 
        $core_dump, $data_structure_reference
    ) = @_;

    my $info = ${$data_structure_reference};
    print "Received from child: \n";
    dd $info;
  }
);

my $pid = $pm->start;
if (!$pid) {
    my ($stdout, $stderr, $exit) = capture {
        sleep 4;
        exec("xecho");
    };
    my $info = {stdout => $stdout, stderr => $stderr, exit=> $exit};
    $pm->finish(0, \$info);
}

print "Master: waiting for child..\n";
$pm->wait_all_children;

输出:

Master: waiting for child..
Received from child: 
{
  exit   => 0,
  stderr => "Can't exec \"xecho\": No such file or directory at ./p.pl line 28.\n",
  stdout => "",
}

非常好!它能否扩展为还能够输出子进程的 $stdout - Jasmine Lognnes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接