Perl で stderr、stdout、および終了コードをすべて一度にキャプチャするにはどうすればよいでしょうか?
質問
Perl から外部プロセスを実行し、その stderr、stdout、およびプロセスの終了コードをキャプチャすることは可能ですか?
これらを組み合わせて実行できるようです。バッククォートを使用して標準出力を取得し、IPC::Open3 を使用して出力をキャプチャし、system() を使用して終了コードを取得します。
stderr、stdout、および終了コードをすべて一度にキャプチャするにはどうすればよいですか?
解決
IPC::Open3 のドキュメントをもう一度読むと、呼び出す必要があるという注記が表示されます。 待ってください 子プロセスを取得します。これを実行すると、ステータスが次のように表示されます。 $?
. 。終了値は $? >> 8
. 。見る$?
perldoc perlvar で.
他のヒント
(アップデート:これをさらに簡単にするために、IO::CaptureOutput の API を更新しました。)
これを行うにはいくつかの方法があります。ここで 1 つのオプションを使用します。 IO::CaptureOutput モジュール:
use IO::CaptureOutput qw/capture_exec/;
my ($stdout, $stderr, $success, $exit_code) = capture_exec( @cmd );
これは Capture_exec() 関数ですが、IO::CaptureOutput には、Perl 出力または外部プログラムからの出力をキャプチャするために使用できる、より一般的な Capture() 関数もあります。そのため、Perl モジュールが外部プログラムを使用している場合でも、出力を取得できます。
また、外部プログラムや Perl 出力をキャプチャする他のモジュールに IPC::Open3 を使用する代わりに、STDOUT と STDERR をキャプチャ (またはマージ) する単一のアプローチだけを覚えておくだけでよいことも意味します。
STDERR の内容が不要な場合は、次の Capture() コマンドを使用します。 IPC::システム::シンプル モジュールはほぼあなたが求めているものです:
use IPC::System::Simple qw(capture system $EXITVAL);
my $output = capture($cmd, @args);
my $exit_value = $EXITVAL;
Capture() を単一の引数とともに使用してシェルを呼び出すことも、複数の引数を指定してシェルを確実に回避することもできます。引数が 1 つであってもシェルを呼び出さない Capturex() もあります。
Perl の組み込みシステム コマンドやバッククォート コマンドとは異なり、IPC::System::Simple は Windows では完全な 32 ビット終了値を返します。また、コマンドを開始できない場合、シグナルによって終了した場合、または予期しない終了値を返した場合にも、詳細な例外がスローされます。これは、多くのプログラムにとって、出口値を自分でチェックするのではなく、IPC :: System :: Simple The Hard Workを実行することを意味します。
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()
と system()
, 、 両方 STDOUT
STDERR はスクリプトと同じ場所に移動します。 STDOUT
そして STDERR,
そうでない限り、 system()
コマンドはそれらをリダイレクトします。バッククォートと open()
だけ読んでください STDOUT
あなたの命令の。
open を指定して次のようなものを呼び出して、両方をリダイレクトすることもできます。 STDOUT
そして STDERR
.
open(PIPE, "cmd 2>&1 |");
リターンコードは常に次の場所に保存されます。 $?
によって指摘されたように @マイケル・カーマン.
非常に複雑になってきた場合は、Expect.pm を試してみるとよいでしょう。しかし、プロセスへの入力の送信も管理する必要がない場合、これはおそらくやりすぎです。
見つけました IPC:実行3 とても役に立ちます。すべての子パイプをグロブまたは変数に転送できます。とても簡単に!そして終了コードは$?に格納されます。
以下は、数値であることがわかっていた標準エラー出力を取得する方法です。この 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);