簡體   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