2

bp_genbank2gff3.pl引数としてgenbankを取得する別のperlスクリプトから(bioperlパッケージ)を実行しようとしています。

これは機能しません(出力ファイルは生成されません):

   my $command = "bp_genbank2gff3.pl -y -o /tmp $ARGV[0]";

   open( my $command_out, "-|", $command );
   close $command_out;

しかし、これはします

   open( my $command_out, "-|", $command );
   sleep 3; # why do I need to sleep?
   close $command_out;

なんで?

私はcloseそれがコマンドが完了するまでブロックすることになっていると思いました:

パイプされたファイルハンドルを閉じると、親プロセスは子プロセスが終了するのを待ちます...(http://perldoc.perl.org/functions/open.htmlを参照)。

編集

これを最後の行として追加しました:

say "ret=$ret, \$?=$?, \$!=$!";

どちらの場合も、印刷出力は次のとおりです。

ret=, $?=13, $!=

(つまりclose、どちらの場合も失敗しましたよね?)

4

2 に答える 2

5

$? = 13子プロセスがSIGPIPEシグナルによって終了したことを意味します。外部プログラム(bp_genbank2gff3.pl)が、プログラムへのパイプに出力を書き込もうとしましたperl。しかし、perlプログラムはパイプの端を閉じたため、OSSIGPIPEは外部プログラムにを送信しました。

sleep3秒間実行すると、OSがプログラムを強制終了する前にプログラムを3秒間実行することになります。これにより、プログラムは何かを実行できるようになります。ただし、パイプの容量には制限があるため、親perlスクリプトがパイプから読み取っていない場合、および外部プログラムが標準出力に大量に書き込んでいる場合、外部プログラムの書き込み操作は最終的にブロックされ、実際には3秒は得られない可能性があります。あなたの外部プログラムからの努力の。

回避策は、外部プログラムを破棄する場合でも、外部プログラムからの出力を読み取ることです。

open( my $command_out, "-|", $command );
my @ignore_me = <$command_out>;
close $command_out;


更新:コマンドの出力を本当に気にしない場合は、出力を次SIGPIPEの場所にリダイレクトすることで問題を回避できます。/dev/null

open my $command_out, "-|", "$command > /dev/null";
close $command_out;     # succeeds, no SIGPIPE

もちろん、出力を無視するのにそれほど苦労する場合は、を使用することをお勧めしますsystem


追加情報:OPが言うように、パイプされたファイルハンドルを閉じると、親は子が終了するのを待ちます(を使用するwaitpidなどして)。しかし、待機を開始するに、パイプの端を閉じます。この場合、その端は、子プロセスが標準出力を書き込んでいるパイプの読み取り端です。次に子が標準出力に何かを書き込もうとすると、OSはそのパイプの読み取り端が閉じていることを検出し、子プロセスにを送信してそれを強制終了し、親SIGPIPEのステートメントをすばやく終了させます。close

于 2010-08-13T15:50:55.823 に答える
0

あなたが何をしようとしているのかわかりませんが、この場合はおそらくシステムの方が優れています...

于 2010-08-13T13:57:47.187 に答える