0

Hans Lub hereの提案にIPC::Open3を使用しています。

私の問題は、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モジュールの内部を見ることは、私の現在の理解を超えています.

4

2 に答える 2

1

open3問題は、渡すファイルハンドルの使用方法にあると思います。たとえば、使用すると、>&STDOUTファイルハンドルが複製され、複製が子プロセスに渡され、親のコピーが閉じられます。つまり、同じことを 2 度目に行うと、閉じたファイル ハンドルを複製することになり、目的の効果が得られません。

これを回避する唯一の方法は、ファイル ハンドルを個別に複製し、その複製を子プロセスに渡すことです。複製の親のコピーが閉じられていても、元のコピーがまだ残っているため、問題になりませんSTDOUT。残念ながら、各open3呼び出しにさらに 3 つのステートメントが追加されるため、このようにサブルーチンで全体をラップすることをお勧めします。

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::Select、子出力から独自のSTDOUTandへのコピーを行うために混乱しSTDERRます。

言うようnwellnhofに、子がそれを使用しない場合STDIN(コマンドの場合のように) 、最初のパラメーターとしてls渡すことができます。undefこれにより、3 つの標準ハンドルのいずれかを複製する手間が省けます。

于 2015-03-16T11:57:18.607 に答える