[英]How to check if command executed with IPC::open3 is hung?
我正在使用以下脚本从作为参数传递的命令中捕获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”借来的。
您可以使用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
。 can_read
的参数是以秒为单位的超时。 sysread
用于非缓冲IO。 基于此答案,我提出了以下解决方案。
但是,像nwellnhof的示例中那样使用select
和避免信号看上去更简洁,这就是为什么我接受了它。 如果有人感兴趣,我会在这里发布:
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;
};
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.