web-dev-qa-db-ja.com

外部コマンドを実行してその出力をPerlでキャプチャするにはどうすればよいですか?

私はPerlを初めて使用し、次のシナリオで外部コマンド(prgと呼びます)を実行する方法を知りたいです。

  1. prgを実行し、そのstdoutのみを取得します。
  2. prgを実行し、そのstderrのみを取得します。
  3. prgを実行し、そのstdoutstderrを別々に取得します。
18
gameover

バックティックを使用して外部プログラムを実行し、そのstdoutstderrをキャプチャできます。

デフォルトでは、バッククォートはstderrを破棄し、外部プログラムのstdoutのみを返します。

$output = `cmd`;

プログラムcmdのstdoutをキャプチャし、stderrを破棄します。

stderrのみをキャプチャするには、シェルのファイル記述子を次のように使用できます。

$output = `cmd 2>&1 1>/dev/null`;

stdoutstderrの両方をキャプチャするには、次のようにします。

$output = `cmd 2>&1`;

上記を使用すると、stderrstdoutを区別できなくなります。 stdoutstderrから分離するには、両方を別のファイルにリダイレクトし、ファイルを読み取ることができます。

`cmd 1>stdout.txt 2>stderr.txt`;
27
codaddict

IPC :: Open または IPC :: Run を使用できます。また、 外部コマンドからSTDERRをキャプチャするにはどうすればよいですか from perlfaq8 をお読みください。

10
ghostdog74

ほとんどの場合、 qx// 演算子(またはバッククォート)。文字列を補間し、シェルで実行するため、リダイレクトを使用できます。

  • コマンドのSTDOUTをキャプチャするには(STDERRは影響を受けません):

    $output = `cmd`;
    
  • コマンドのSTDERRとSTDOUTを一緒にキャプチャするには:

    $output = `cmd 2>&1`;
    
  • コマンドのSTDERRをキャプチャし、そのSTDOUTを破棄するには(ここでは順序付けが重要です)。

    $output = `cmd 2>&1 1>/dev/null`;
    
  • STDERRをキャプチャするためにコマンドのSTDOUTとSTDERRを交換し、そのSTDOUTを残して古いSTDERRを出力するには:

    $output = `cmd 3>&1 1>&2 2>&3 3>&-`;
    
  • コマンドのSTDOUTとそのSTDERRの両方を別々に読み取るには、それらを別々にファイルにリダイレクトし、プログラムの完了時にそれらのファイルから読み取るのが最も簡単です。

    system("program args 1>program.stdout 2>program.stderr");
    
8
Eugene Yarmash

上記のEugeneの回答(彼の回答にコメントすることはできません)に注意してください。SDTOUTとSTDERRを交換する構文は、Unix(kshやbashなどのUnixenのようなシェル)では有効ですが、WindowsCMDでは有効ではありません。 (エラー:3>& was unexpected at this time.)。

WindowsCMDおよびWindows上のPerlでの適切な構文は次のとおりです。

Perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2};

次のコマンドに注意してください。

nslookup 255.255.255.255

sTDOUTで(のような)を生成します:

Server:  mymodem.lan
Address:  fd37:c01e:a880::1

およびSTDERR:

*** mymodem.lan can't find 255.255.255.255: Non-existent domain

この構文が次のCMD/Perl構文で機能することをテストできます。

最初:

Perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2}; $r=~s/[\n\r]//eg; print qq{on STDOUT qx result=[$r]};"

あなたが得る:Server: mymodem.lan Address: fd37:c01e:a880::1 on STDOUT qx result=[*** mymodem.lan can't find 255.255.255.255: Non-existent domain]

次に

Perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2}; $r=~s/[\n\r]//eg; print STDOUT qq{on STDOUT qx result=[$r]};" 2>&1 1>NUL:

あなたが得る:Server: mymodem.lan Address: fd37:c01e:a880::1

QED [fr:CQFD]

Qxまたはbackticksコマンドの戻り文字列としてstderrとstdoutの両方を取得することはできないことに注意してください。生成されたコマンドによって返されるエラーテキストの長さがN行であることが確実にわかっている場合でも、Eugeneなどが説明するようにSTDERRをSTDOUTにリダイレクトできますが、qxで返されたテキストをスカラー文字列ではなく配列にキャプチャします。 STDERRフローは配列に返されますbefore STDOUTなので、配列の最初のN行はSDTERR行になります。お気に入り:

@r=qx{nslookup 255.255.255.255 2>&1};
$r[0] is "*** mymodem.lan can't find 255.255.255.255: Non-existent domain"

ただし、もちろん、is STDERRおよび厳密にN行(@r[0..N-1]に格納されている)のエラーテキストがあることを確認する必要があります。 。そうでない場合、唯一の解決策は上記のように一時ファイルを使用することです。

1