处理挂起进程的输出

时间:2011-05-10 00:15:12

标签: perl

我想用perl脚本运行一些测试可执行文件,解析它们的STDOUT,并根据STDOUT包含的内容返回一个退出值。我对perl不太熟悉,所以这有点难度。

我遇到的问题是确保即使测试可执行文件崩溃或挂起,我的perl脚本也会收到任何输出。

目前,我正在使用闹钟超时。如果它挂起,我想只是采取我能做的任何数据并继续解析。不幸的是,使用我当前的执行方法,如果它挂起,我没有数据,僵尸进程永远存在。

获得测试输出的我(可能是天真的)版本就是这样。

#!/usr/bin/perl
use strict;
use warnings;

my @output;

eval {
   local $SIG{ALRM} = sub {die "alarm\n"};
   alarm 15;
   @output = `testExecutable`;
   alarm 0;
};

if ($@) {
  die unless $@ eq "alarm\n";
  print "timed out\n";
}
else {
  print "didn't time out\n";
}

print @output;

基本上,我需要执行testExecutable,以便在警报响起之前访问它输出的任何数据,然后在警报处理程序中终止testExecutable进程。

如有必要,我可以修改测试可执行文件。环顾四周,似乎缓冲可能会引起一些担忧。

2 个答案:

答案 0 :(得分:1)

问题在于,使用反引号运算符只会在完成时填充perl变量。所以你应该从perl管道读取。所以像这样:

#!/usr/bin/env perl
use strict;
use warnings;

my @output;

eval {
    local $SIG{ALRM} = sub {die "alarm\n"};
    alarm 15;
    open my $pipe_handle, '-|', 'testExecutable' or die "open error: $!";
    while (my $line = <$pipe_handle>) {
        push @output, $line;
    }
    close $pipe_handle;
    alarm 0;
};

if ($?) {
    print "testProgram failed\n";
} elsif ($@) {
    die unless $@ eq "alarm\n";
    print "timed out\n";
} else {
    print "didn't time out\n";
}

print @output;

请记住,可能会有一些缓冲区继续存在,所以你仍然可能错过了一些输出。

编辑:添加以检查$?以检查子计划的状态

答案 1 :(得分:1)

将外部命令的输出写入文件,并在过程完成时读取文件(正常或超时)。就像Sodved说的那样,最好能让外部程序经常刷新输出。

my $output_file = '/tmp/foo';
eval {
   local $SIG{ALRM} = sub {die "alarm\n"};
   alarm 15;
   system("testExecutable > $output_file 2>&1");
   alarm 0;
};

# whether successful or not, there could be output in $output_file ...
open my $fh, '<', $output_file;
@output = <$fh>;
close $fh;
unlink $output_file;