繁体   English   中英

两次使用open3时在IPC :: Open3中发出警告

[英]Warning within IPC::Open3 when using open3 twice

我正在使用IPC :: Open3作为此处的Hans Lub的建议。

我的问题是open3调用第一次可以正常工作,但是随后的调用会返回警告:

Use of uninitialized value in numeric ne (!=) at /usr/lib/perl5/5.8.8/IPC/Open3.pm line 215.

我正在使用的代码示例如下所示:

use  IPC::Open3;

my $pid;
# dup the old standard output and error 
open(OLDOUT, ">&STDOUT") or die "Can't dup STDOUT: $!\n";
open(OLDERR, ">&STDERR") or die "Can't dup STDERR: $!\n";

my $transcript_file = "transcript.temp";
# reopen stdout and stderr
open (STDOUT, "|tee -i $transcript_file") or die "Can't reopen STDOUT: $!\n";
open (STDERR, ">&STDOUT")              or die "Can't reopen STDERR: $!\n";

# print statements now write to log
print "Logging important info: blah!\n";
print STDERR "OOPS!\n";

#eval { $pid = open3("\*STDIN", "\*OLDOUT", "\*OLDERR", "ls"); }; # Tried this, but doesnt seem to help. Output does not appear on STDOUT.
eval { $pid = open3(">&STDIN", ">&OLDOUT", ">&OLDERR", "ls"); }; #This works correctly
waitpid( $pid, 0 );

eval { $pid = open3(">&STDIN", ">&OLDOUT", ">&OLDERR", "ls"); }; #First warning
waitpid( $pid, 0 );

eval { $pid = open3(">&STDIN", ">&OLDOUT", ">&OLDERR", "ls"); }; #Second warning
waitpid( $pid, 0 );

如果我想让别人解决我的问题,我深表歉意,但是我似乎无法解决这个问题,而在Perl模块内部查找超出了我目前的理解。

将相同的STDIN分配给多个并行进程是没有意义的。 因此, open3假定您告诉open3使用的句柄没有被其他任何东西使用,因此它将关闭它。

看起来您的孩子没有使用您提供的STDIN,因此您应该提供/dev/null的句柄。

open(local *CHILD_STDIN, '<', '/dev/null') or die $!;
$pid = open3('<&CHILD_STDIN', '>&STDOUT', '>&STDERR', @cmd);

我认为问题是open3使用传递的文件句柄的方式。 如果使用>&STDOUT则将复制文件句柄,将复制传递给子进程,并关闭父级的副本。 这意味着您第二次执行相同的操作时将复制关闭的文件句柄,但效果不理想。

我可以看到的解决此问题的唯一方法是分别复制文件句柄并将复制对象传递给子进程。 关闭父级的dupes副本并不重要,因为它仍然具有原始的STDOUT等。不幸的是,它在每个open3调用中又添加了三个语句,因此您可能希望将整个内容包装在一个子例程中,如下所示。

my_open3('ls');
my_open3('ls');
my_open3('ls');

sub my_open3 {

  my @cmd = @_;
  my $pid;

  open IN_COPY,  '<&', STDIN  or die "Couldn't dup STDIN: $!";
  open OUT_COPY, '>&', STDOUT or die "Couldn't dup STDOUT: $!";
  open ERR_COPY, '>&', STDERR or die "Couldn't dup STDERR: $!";

  eval {
    $pid = open3('>&IN_COPY', '>&OUT_COPY', '>&ERR_COPY', @cmd);
  };

  waitpid $pid, 0;
}

这不是最好的解决方案,因此,如果有人能看到更好的结果,请发出提示。我能看到的唯一选择是让父级保留自己的标准IO句柄,并使用全新的IO句柄与每个子进程进行通信。时间。 然后,父级将与IO::Select发生混乱,以将其从子级输出复制到其自己的STDOUTSTDERR

正如nwellnhof所说,如果孩子不使用其STDIN (与ls命令的情况一样),则只需传递undef作为第一个参数即可。 这样可以避免重复使用三个标准手柄之一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM