2013-08-22 101 views
2

我使用以下腳本從作爲參數傳遞的命令中捕獲STDINSTDOUTSTDERR如何檢查IPC :: open3執行的命令是否被掛起?

#!/usr/bin/perl 

use strict; 
use warnings; 

use IPC::Open3; 

local(*CMD_IN, *CMD_OUT, *CMD_ERR); 

my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $ARGV[0]); 

close(CMD_IN); 

my @stdout_output = <CMD_OUT>; 
my @stderr_output = <CMD_ERR>; 

close(CMD_OUT); 
close(CMD_ERR); 

waitpid ($pid, 0); # reap the exit code 

print "OUT:\n", @stdout_output; 
print "ERR:\n", @stderr_output; 

這一切都很好,除了我不確定如何監視命令傳遞是否掛起。你能提出一個建議嗎?

我借用了這個片段,最初來自'編程Perl'。

回答

5

您可以使用selectIO::Select並提供超時。如果你想從stdout和stderr中讀取,你應該這樣做(參見文檔IPC::Open3)。

下面是一個使用IO::Select一個示例程序:

#!/usr/bin/perl 

use strict; 
use warnings; 

use IO::Select; 
use IPC::Open3; 
use Symbol 'gensym'; 

my ($cmd_in, $cmd_out, $cmd_err); 
$cmd_err = gensym; 
my $pid = open3($cmd_in, $cmd_out, $cmd_err, $ARGV[0]); 

close($cmd_in); 

my $select = IO::Select->new($cmd_out, $cmd_err); 
my $stdout_output = ''; 
my $stderr_output = ''; 

while (my @ready = $select->can_read(5)) { 
    foreach my $handle (@ready) { 
     if (sysread($handle, my $buf, 4096)) { 
      if ($handle == $cmd_out) { 
       $stdout_output .= $buf; 
      } 
      else { 
       $stderr_output .= $buf; 
      } 
     } 
     else { 
      # EOF or error 
      $select->remove($handle); 
     } 
    } 
} 

if ($select->count) { 
    print "Timed out\n"; 
    kill('TERM', $pid); 
} 

close($cmd_out); 
close($cmd_err); 

waitpid($pid, 0); # reap the exit code 

print "OUT:\n", $stdout_output; 
print "ERR:\n", $stderr_output; 

注:

  • 我使用的詞彙瓦爾文件句柄。這需要使用gensym作爲stderr句柄。
  • can_read的參數是以秒爲單位的超時。
  • 我使用sysread作爲非緩衝IO。
  • 如果發生讀取超時,我終止孩子。
+0

非常感謝!我實際上實現了一些可以完成這項工作的東西,但我寧願避免使用信號並改用您的解決方案。無論如何,如果其他人感興趣,我會發布它。 – Nobilis

1

我根據this的答案提出了以下解決方案。

但是使用select並避免信號,因爲在nwellnhof的例子看起來更清潔,這就是爲什麼我接受它。如果有人感興趣,我在此張貼:

my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd); 

if ($pid > 0){ 
    eval{ 
     local $SIG{ALRM} = sub {kill 9, $pid;}; 
     alarm 6; 
     waitpid($pid, 0); 
     alarm 0; 
    }; 
}