如何检查使用 IPC::open3 执行的命令是不是挂起?
Posted
技术标签:
【中文标题】如何检查使用 IPC::open3 执行的命令是不是挂起?【英文标题】:How to check if command executed with IPC::open3 is hung?如何检查使用 IPC::open3 执行的命令是否挂起? 【发布时间】:2013-08-22 06:49:18 【问题描述】:我正在使用以下脚本从作为参数传递的命令中捕获STDIN
、STDOUT
和STDERR
。
#!/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;
除了我不确定如何监控传递的命令是否挂起之外,一切都很好。你能推荐一个方法吗?
我最初从“Programming Perl”借用了这个 sn-p。
【问题讨论】:
【参考方案1】:您可以使用select
或IO::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。
如果出现读取超时,我会终止子进程。
【讨论】:
非常感谢!我实际上实现了一些可以完成这项工作的东西,但我宁愿避免使用信号并使用您的解决方案。如果其他人有兴趣,我会发布它。【参考方案2】:我根据this 的回答提出了以下解决方案。
但是,使用select
并避免使用 nwellnhof 示例中的信号看起来更干净,这就是我接受它的原因。如果有人感兴趣,我会在这里发布:
my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd);
if ($pid > 0)
eval
local $SIGALRM = sub kill 9, $pid;;
alarm 6;
waitpid($pid, 0);
alarm 0;
;
【讨论】:
以上是关于如何检查使用 IPC::open3 执行的命令是不是挂起?的主要内容,如果未能解决你的问题,请参考以下文章