2016-04-07 15 views
1

私はPerlを使用して外部プログラムを実行していますが、実行中に特定の文字列を返す場合はその実行を終了したいと考えています。以下のコードは実行を中断しますが、最後の行(close)が実行されるとエラーメッセージが返されます。エラーなしのPerl終了パイプ

open (my $out, "-|", "usfos $memory<input-$cpu.scr"); 
while (<$out>) { 
    if ($_ =~ /MIN STEP LENGTH/) { 
     last; 
    } 
} 
close $out; 

これは、印刷されたエラーの一部(外部プログラムは、エラーメッセージを返す)である:

...forrtl: The pipe is being closed. 
forrtl: severe (38): error during write, unit 6, file CONOUT$ 

だから私はPerlが閉じられたハンドルへの書き込みしようとしているからだと思います。何が印刷されるのを避けるには?

+0

perlは書き込みしようとしていませんが、これは書き込みを行わないパイプです。あなたの外部のプログラムがエラーを出すものだと思われます。 –

答えて

4

close $outのときに外部プログラムを終了していない場合は、STDOUTを閉じています。

プログラムを閉じるには、プロセスIDを取得してから適切な信号を送信する必要があります。 open呼び出しはpidを返し、保存するだけです。その後、条件が満たされたときに信号を送信します。

use Scalar::Util qw(openhandle); # to check whether the handle is open 

my $pid = open (my $out, "-|", "usfos $memory<input-$cpu.scr") 
       // die "Can't fork: $!"; #/stop editor red coloring 
while (<$out>) { 
    if (/MIN STEP LENGTH/) { 
     kill "TERM", $pid; # or whatever is appropriate; add checks 
     close $out;   # no check: no process any more so returns false 
     last; 
    } 
} 
# Close it -- if it is still open. 
if (openhandle($out)) {   
    close $out or warn "Error closing pipe: $!"; 
} 

openopentut、およびcloseを参照してください。

のFortranのエラーが存在しないコンソール(STDOUT)への書き込みについては確かなので、あなたが問題を正しく診断されていることに私には思える:条件が一致したとして、あなたは(last)読み取りを停止し、その後、プログラムのSTDOUTを閉じますこれは、次に試行された書き込みで報告されたエラーを引き起こします。

いくつかのメモ。パイプを閉じると、他のプロセスが終了するのを待ちます。他端のプログラムがcloseに知られるような問題を抱えている場合は、$?に質問する必要があります。他のプログラムが書き込まれる前にパイプを閉じると、SIGPIPEが送信されます。 close ドキュメント

からファイルハンドルをパイプで連結された、オープン、クローズを返すから来た場合はfalseの場合は、そのプログラムが非ゼロのステータスで終了した場合に関与する他のシステムコールの一つが故障しましたか。唯一の問題は、プログラムが非ゼロで終了したことである場合、$! 0に設定されます。パイプを閉じると、パイプ上で実行されているプロセスが終了するのを待ちます。パイプの出力を後で見たい場合は、そのコマンドの終了ステータス値を暗黙的に$?に入れます。 $ {^ CHILD_ERROR_NATIVE}です。
...
パイプの読取り側を処理終了前に閉じると、書込み側はSIGPIPEを受け取って結果を書き込みます。もう一方の端で処理できない場合は、パイプを閉じる前にすべてのデータを必ず読み込んでください。


 オブジェクトがSTDOUTがそのファイルハンドル(一度条件が満たされている)を閉じるために、ファイルハンドルに接続されているプロセスを殺すために添加します。プロセスがまだ書き込んでいる間に最初にハンドルを閉じると、わからないプロセスにSIGPIPEが送信されています。 (信号を処理していますか?)一方で、最初に終了すると、$outに接続されたプロセスが終了したため、close($out)は正常に完了できません。プロセスが殺された後(killが成功した場合)、それ偽であるように、コードは、closeへの呼び出しからの復帰をチェックしない理由

です。ループの後でハンドルを閉じる前にまだハンドルが開いているかどうかがチェックされます。パッケージScalar::Utilはこれに使用され、別のオプションはfilenoです。コードでkillがジョブを実行したかどうかはチェックされず、必要に応じて追加されます。


Windowsシステムでは、子供のプロセスIDを見つける必要があるため、少し異なります。これを行うには、名前を使用してからWin32::Process::Killを使用するか、killを使用して終了します。 (または、以下、このすべてを行う必要があり、Windowsのコマンドを参照してください。)プロセスIDがWin32::Process::Infoを使用しWin32::Process::List

use Win32::Process::Kill; 
use Win32::Process::List; 
my $pobj = Win32::Process::List->new(); 
my %proc = $pobj->GetProcesses(); 
my $exitcode; 
foreach my $pid (sort { $a <=> $b } keys %proc) { 
    my $name = $proc{$pid}; 
    if ($name =~ /usfos\.exe/) { 
     Win32::Process::KillProcess($pid, \$exitcode); 
     # kill 21, $pid; 
     last; 
    } 
} 
  • 使用

    • のいずれかを試してみてください見つけるために。 this postを参照してください。

      use Win32::Process::Info; 
      Win32::Process::Info->Set(variant=>'WMI'); # SEE DOCS about WMI 
      my $pobj = Win32::Process::Info->new(); 
      foreach my $pid ($pobj->ListPids) { 
          my ($info) = $pobj->GetProcInfo($pid); 
          if ($info->{CommandLine} =~ /^usfso/) { # command-line, not name 
           my $proc = $info->{ProcessId}; 
           kill 2, $proc; 
           last; 
          } 
      } 
      

      このモジュールはまた、提出$ppid(S)のすべての子を同定する方法Subprocesses([$ppid,...])を提供することに留意されたいです。これは、$ppidでインデックス付けされ、$ppidがサブミットされたすべてのサブプロセスの$pidである配列-refを含むハッシュを返します。

      use Win32::Process::Info; 
      Win32::Process::Info->Set(variant=>'WMI'); 
      my $pobj = Win32::Process::Info->new(); 
      my %subproc = $pobj->Subprocesses([$pid]); # pid returned by open() call 
      my $rkids = $subproc{$pid}; 
      foreach my $kid (@$rkids) { 
          print "pid: $kid\n";      # I'd first check what is there 
      } 
      
    • は、私は今、この権利のいずれかをテストすることはできませんプロセスとその子

      system("TASKKILL /F /T /PID $pid"); 
      

    を終了する必要があり、WindowsのコマンドTASKKILL /Tに走りました。

  • +0

    私は 'kill'を使うと親プロセスID(cmd.exe)だけを閉じます。私は 'kill -9、$ pid;'を試しましたが、これは同じです。エラーを回避するために子プロセス(usfos.exe)を終了する必要がありますが、IDを取得する方法はわかりません。あるいは、私はCTRL + c( "\ x03")をcmdに送ることができます。これは子プロセスを強制終了しますが、これを行う方法がわかりません。 –

    +0

    @charleshendry私はWindowsの方法で自分の答えを更新しました。私は今テストすることができません。 – zdim

    関連する問題