如何检查IPC :: open3执行的命令是否挂起?

Nob*_*lis 2 perl ipc

我正在使用以下脚本来捕获STDIN,STDOUTSTDERR从作为参数传递的命令中捕获.

#!/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;
Run Code Online (Sandbox Code Playgroud)

这一切都很好,除了我不知道如何监视传递的命令是否挂起.你能建议一个方法吗?

我从"Programming Perl"借用了这个片段.

nwe*_*hof 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;
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 我使用lexical vars作为文件句柄.这需要使用gensymstderr手柄.
  • 参数can_read是以秒为单位的超时.
  • sysread用于非缓冲IO.
  • 如果有读取超时,我会终止孩子.