Perl:open3 但对于 n 个文件描述符

Posted

技术标签:

【中文标题】Perl:open3 但对于 n 个文件描述符【英文标题】:Perl: open3 but for n file descriptors 【发布时间】:2013-07-15 17:15:48 【问题描述】:

open3 只接受 STDIN、STDOUT 和 STDERR。如果正在运行的命令使用其他文件描述符,则 open3 无法捕获这些:

echo foo # Can be captured
echo foo >&2 # Can be catured
echo foo >&3 # Cannot be captured (with open3)

我已经研究过 IPC::Run::run 似乎能够处理这个问题,但我也需要 PID,但我发现 IPC::Run::run 没有办法给我。

是否有一个 openN 或 IPC::Run::run 方法可以给我 PID?

背景

这是用于 GNU Parallel 的可能扩展,因此您可以这样做:

parallel 'echo  start >&3;sleep 10;echo  end >&3' ::: a b c 3>out.file

无需混合来自不同作业的输出。 GNU Parallel 需要跟踪每个 pid - 尤其是在使用 --keep-order 时。

【问题讨论】:

你为什么要这个 pid? IPC::Open3 不会阻止您在 fd3 上放置管道。它只是不会为你做。 孩子的 pid 在 IPC::Run 内部是已知的。只需将IPC::Run::run 替换为IPC::Run::start 并转储返回的对象。不幸的是,这没有记录在案,所以你自己...... @ikegami 如果您以echo start >&3;sleep 10;echo end >&3 作为正在运行的命令并将 fd3 分配给 perl 文件句柄来发布答案,我将接受它作为答案。 【参考方案1】:

fd3 已经存在,所以你需要做的就是确保孩子继承它。由于它是继承的,因此您根本不需要做任何事情。

$ perl -e'
   system "echo foo >&3";
' 3>bar

$ cat bar
foo

但是如果你想确保它是继承的,你可以使用下面的

$ perl -e'
   use Fcntl qw( F_GETFD F_SETFD FD_CLOEXEC );
   if (open(my $fh, ">&=", 3)) 
      my $flags = fcntl($fh, F_GETFD, 0)
         or die $!;
      fcntl($fh, F_SETFD, $flags & ~FD_CLOEXEC)
         or die $!;
   

   system "echo foo >&3";
' 3>bar

$ cat bar
foo

【讨论】:

我不希望它继承。我想把孩子在 fd3 上打印的所有内容放在一个文件中,当孩子死时,在 fd3 上打印文件。我知道如何做最后一部分(孩子死后打印)。 请记住,在 GNU Parallel 中,我可以让多个孩子同时写入每个他们的 fd3,并且我不希望输出混合,因此 GNU Parallel 需要在输出到达之前捕获它GNU Parallel 的 fd3。 如果你可以制作 open4(fd0,fd1,fd2,fd3,cmd,arg) 并基于 open3 那就没问题了。

以上是关于Perl:open3 但对于 n 个文件描述符的主要内容,如果未能解决你的问题,请参考以下文章

Perl open3读取gnuplot块的管道句柄

如何在 perl 中使用标量作为 open3 的输入

Perl 行为差异关闭由 open() 产生的子进程与 IPC::Open3

perl IPC:Open3 最小通过 perlcritic?

我们在 C 或 C++ 中是不是有类似于 IPC::Open3 的 perl

Perl 中带有 XMLRPC::Lite 的错误文件描述符