Perl から外部プロセスを実行し、その stderr、stdout、およびプロセス終了コードをキャプチャすることは可能ですか?
これらの組み合わせを実行できるようです。たとえば、バックティックを使用して stdout を取得し、IPC::Open3 を使用して出力をキャプチャし、system() を使用して終了コードを取得します。
stderr、stdout、および終了コードを一度にキャプチャするにはどうすればよいですか?
(更新: IO::CaptureOutput の API を更新して、これをさらに簡単にしました。)
これを行うにはいくつかの方法があります。IO::CaptureOutputモジュールを使用した 1 つのオプションを次に示します。
use IO::CaptureOutput qw/capture_exec/;
my ($stdout, $stderr, $success, $exit_code) = capture_exec( @cmd );
これは capture_exec() 関数ですが、IO::CaptureOutput には、Perl 出力または外部プログラムからの出力のいずれかをキャプチャするために使用できる、より一般的な capture() 関数もあります。そのため、Perl モジュールがたまたま外部プログラムを使用している場合でも、出力が得られます。
また、外部プログラムに IPC::Open3 を使用したり、Perl 出力をキャプチャする他のモジュールを使用したりする代わりに、STDOUT と STDERR をキャプチャする (またはそれらをマージする) ための単一のアプローチを覚えるだけでよいことも意味します。
IPC::Open3 のドキュメントを読み直すと、waitpidを呼び出して子プロセスを取得する必要があることに注意してください。これを行うと、ステータスが で使用可能になります$?
。終了値は$? >> 8
です。$?
perldoc perlvarを参照
してください。
STDERRの内容が必要ない場合は、IPC :: System :: Simpleモジュールからのcapture()コマンドは、ほぼ正確に次のようになります。
use IPC::System::Simple qw(capture system $EXITVAL);
my $output = capture($cmd, @args);
my $exit_value = $EXITVAL;
シェルを呼び出すために単一の引数でcapture()を使用するか、シェルを確実に回避するために複数の引数を使用できます。引数が1つであっても、シェルを呼び出さないcapturex()もあります。
Perlの組み込みシステムおよびbackticksコマンドとは異なり、IPC :: System :: Simpleは、Windowsでは完全な32ビットの終了値を返します。また、コマンドを開始できない場合、シグナルで停止した場合、または予期しない終了値を返した場合にも、詳細な例外がスローされます。これは、多くのプログラムでは、終了値を自分でチェックするのではなく、IPC :: System::Simpleを使用してハードワークを実行できることを意味します。
use IPC::System::Simple qw(system capture $EXIT_ANY);
system( [0,1], "frobincate", @files); # Must return exitval 0 or 1
my @lines = capture($EXIT_ANY, "baznicate", @files); # Any exitval is OK.
foreach my $record (@lines) {
system( [0, 32], "barnicate", $record); # Must return exitval 0 or 32
}
IPC :: System :: Simpleは純粋なPerlであり、依存関係はなく、UnixシステムとWindowsシステムの両方で機能します。残念ながら、STDERRをキャプチャする方法を提供していないため、すべてのニーズに適しているとは限りません。
IPC :: Run3は、3つの一般的なファイルハンドルすべてを再配管するためのクリーンで簡単なインターフェイスを提供しますが、残念ながら、コマンドが成功したかどうかを確認しないため、$を検査する必要がありますか?手動で、これはまったく楽しいことではありません。$を検査するためのパブリックインターフェイスを提供しますか?$を調べてから、IPC :: System :: Simpleのやることリストに載っているものは何ですか?クロスプラットフォームの方法で、私が誰にも望んでいるタスクではありません。
IPC ::名前空間には、他にも支援を提供する可能性のあるモジュールがあります。YMMV。
ではごきげんよう、
ポール
外部コマンドを実行するには、次の 3 つの基本的な方法があります。
system $cmd; # using system()
$output = `$cmd`; # using backticks (``)
open (PIPE, "cmd |"); # using open()
を使用すると、 と STDERRsystem()
の両方が、スクリプトのand とSTDOUT
同じ場所に移動します。コマンドがそれらをリダイレクトしない限り。コマンドのバッククォートと読み取りのみ。STDOUT
STDERR,
system()
open()
STDOUT
STDOUT
次のようなものを open で呼び出して、 と の両方をリダイレクトすることもできますSTDERR
。
open(PIPE, "cmd 2>&1 |");
@Michael Carman$?
が指摘したように、戻りコードは常に格納されます。
非常に複雑になってきている場合は、Expect.pm を試してみてください。しかし、プロセスへの入力の送信も管理する必要がない場合、それはおそらくやり過ぎです。
IPC:run3が非常に役立つことがわかりました。すべての子パイプをグロブまたは変数に転送できます。とても簡単に!そして、終了コードは $? に格納されます。
以下は、数値であることがわかっているstderrを取得する方法です。cmdは情報変換をstdoutに出力し(>を使用して引数のファイルにパイプしました)、変換の数をSTDERRに報告しました。
use IPC::Run3
my $number;
my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number);
die "Command failed: $!" unless ($run && $? == 0);