1

外部スクリプトを使用するPerlスクリプトを書いています。外部スクリプトは特定のディレクトリから実行する必要があるため、次のことが便利であることがわかりました。

use IPC::System::Simple qw(capture);

my @args = ('external script path...', 'arg1', ...);
my $out = capture( [0], "cd $dir ; @args" );

外部スクリプトがSTDERRに何かを書き込んでも、それでも0を返すことがあります。これらの時間とconfess(またはdie)をキャプチャしたいと思います。外部スクリプトの戻り値を制御していないので、おそらくそのSTDERRをキャプチャできると思ったので、次のようにします。

my ($out, $err) = cool_capture( [0], "cd $dir ; @args" );
say "Output was: $out";
if ($err) {
 die "Error: this was written to STDERR: $err";
}

私に何ができる?

4

2 に答える 2

6

これはPerlFAQでカバーされています。

推定test_appは、1行をstdoutに出力し、1行をstderrに出力するプログラムです。

use IPC::Open3;
use Symbol 'gensym';

my($wtr, $rdr, $err);
$err = gensym;

my $pid = open3($wtr, $rdr, $err, 'test_app');

waitpid($pid, 0);
my $status = $? >> 8;

my $stdout = <$rdr>;
my $stderr = <$err>;

print "out output: $stdout\n";
print "err output: $stderr\n";

print "Exit code: $status\n";

編集:終了コードのキャプチャを含むように更新されたリクエストごと。あなたはまた、perldoc IPC::Open3どちらが言うか尋ねることができます

waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

そして、あなたはその注意と警告のためにとにかく読むべきです。

于 2010-12-07T14:59:47.183 に答える
1

重要な出力がstdoutおよび/またはstderrに書き込まれている場合、またはプロセスの読み取りと書き込みの両方を行っている場合。さまざまなブロッキングの問題を回避するために、I/Oの処理にはさらに注意を払う必要があります。

my ($wtr, $rdr, $err) ;

my $pid = IPC::Open3::open3($wtr, $rdr, $err, @_);

close($wtr);

my $stdout = '';
my $stderr = '';

my $s = IO::Select->new;

$s->add($rdr) if $rdr;
$s->add($err) if $err;

while (my @ready = $s->can_read) {

    foreach my $ioh (@ready) {

        my $bytes_read = sysread($ioh, my $chunk = '', 1024);

        die "read error: $!" unless $bytes_read >= 0;

        if ($bytes_read) {
           ($ioh eq $rdr? $stdout: $stderr) .= $chunk;
        }
    else {
            $s->remove($ioh);
        }
    }
} 

my $pid1;
for (;;) {

    last if kill(0, $pid);

    $pid1 = wait();
    #
    # Wait until we see the process or -1 (no active processes);
    #
    last if ($pid1 == $pid || $pid1 <= 0);
}

プロセスをシャットダウンする前に、読み取りを終了してください。プロセスのstdinに書き込んでいる場合は、上記のselectループに$wtrとsyswriteも追加する必要があります。

編集

理論的根拠:

上記は、単純なケースではおそらくやり過ぎです。この入力と出力の高度な処理は、数Kを超えるデータを移動する可能性が高い場合に役立ちます。

たとえば、「df」コマンドを実行している場合は必要ありません。

ただし、stdin、stdout、またはstderrのいずれかのシステムバッファがいっぱいになると、ブロックが発生する可能性が高くなり、事態がさら​​に複雑になる可能性があります。

子プロセスがstderrおよび/またはstdoutバッファーをいっぱいにすると、ブロックされ、それらがクリアされるのを待つ可能性があります。ただし、stdoutまたはstderrから読み取る前にプロセスが終了するのを待っている場合は、それはデッドロックです。システムコールが終了せず、子プロセスが完了しないことがわかります。

stdinが書き込まれている場合、同様のデッドロックの可能性がありますが、子プロセスは入力を消費できません。これは、子プロセスが入力とstdoutへの書き込みを消費している「パイプ」状況で特に発生する可能性があります。

選択ループは、ブロッキングを回避するためにバッファを段階的にクリアすることです。stdoutとstderrの両方が同時に監視されます。

stdinに書き込み、stdout(パイプ)から読み取る場合は、stdoutとstderrをクリアに保ち、入力を受け取る準備ができたときにのみstdinに書き込む必要があります。

プロセスが終了するのを待つだけで、stdout / stderrの読み取りはおそらく90%の時間で機能します。この返信は、事態がさら​​に複雑になり、プロセスがブロックされ始めたり、デッドロックに陥ったりした場合に、どこかに行くための場所を提供するためのものです。

EDIT2

どちらを使うかというと、簡単に始めて、一生懸命テストすると思います。

Sorpigalのアプローチを採用しますが、データ量が多く、実際のシステムで予想されるより困難な負荷と条件の下で、ストレステストを試してください。

于 2010-12-07T20:20:48.457 に答える