我正在编写一个Perl脚本,该脚本需要在将运行进程的Windows和linux中工作,如果花费的时间太长则将其超时,并假设退出超时则返回退出代码,并假设exitcode为零时返回stdout。而且没有超时。我不需要STDIN或STDERR。我尝试使用IPC::run
,但无法正常工作。
与我最接近的是IPC::Open3
和waitpid($pid, WNOHANG)
。但是我遇到了障碍。我在Windows和Linux上看到了不同的结果。在下面的代码中,我给open3
一个将失败的命令(ping没有任何参数-z
)。在Linux上,代码立即返回负退出代码。在Windows上,命令超时。在Windows命令行上运行ping google.com -z
会立即返回,告诉我没有这样的参数。为什么``waitpid''返回零?
use strict;
use warnings;
use POSIX ":sys_wait_h";
use IPC::Open3;
my $inFH;
my $outFH;
my @cmd = ("ping", "google.com", "-z");
my $pid = open3( $inFH, $outFH, 0, @cmd);
my $counter=0;
my $waitret;
my $exitcode;
do{
$counter++;
$waitret = waitpid($pid,WNOHANG);
$exitcode = $?;
}while( !$waitret and ($counter < 4_000_000));
if ($counter >= 4_000_000) {
print "Command timed out\n";
kill(9, $pid);
} else {
print "Exit Code: $exitcode\n";
}
欢迎其他解决方案。我将waitpid与nohang一起使用的唯一原因是,如果花费的时间太长,则将其杀死。在此期间,我没有其他需要做的处理。 我在Windows上使用Windows 10 Strawberry Perl 5.28 Portable。我的debian机器安装了perl 5.24。
答案 0 :(得分:3)
IPC::Run支持各种timeouts and timers,它们也可以在Win32上运行。
基本:
use warnings;
use strict;
use feature 'say';
use IPC::Run qw(run timeout);
my $out;
eval {
run [ qw(sleep 20) ], \undef, \$out, timeout(2) or die "Can't run: $?"
};
if ($@) {
die $@ if $@ !~ /^IPC::Run: timeout/;
say "Eval: $@";
}
timeout
引发异常,因此eval
。还有其他计时器,其行为更加微妙和易于管理。请参阅文档。
如果捕获的异常不是由IPC::Run
的计时器引起的,则重新引发异常-根据消息中输出的系统上模块的版本判断,该字符串以 IPC开头:: Run:超时。请检查系统上的内容。
我认为,尽管某些事情在Windows上不起作用,但计时器应该可以。我现在无法测试。
据报道,尽管上面的方法有效,但使用了更有意义的命令,SIGBREAK (21)
会在超时时发出,一旦处理,该过程就会继续进行。
在这种情况下,请在处理程序中手动将其终止
use warnings;
use strict;
use feature 'say';
use IPC::Run qw(run harness timeout);
my $out;
my @cmd = qw(sleep 20);
my $h = harness \@cmd, \undef, \$out, timeout(2);
HANDLE_RUN: {
local $SIG{BREAK} = sub {
say "Got $_[0]. Terminate IPC::Run's process";
$h->kill_kill;
};
eval { run $h };
if ($@) {
die $@ if $@ !~ /^IPC::Run: timeout/;
say "Eval: $@";
}
};
为了能够在此处使用模块的kill_kill
,我首先创建一个线束,该线束在安装处理程序时可用,并且在触发时可以在其上调用kill_kill
。 / p>
另一种方法是查找进程ID(使用Win32::Process::Info或Win32::Process::List),
并以kill
或Win32::Process或TASKKILL
终止。参见this post(下半部分)。
仅将一个块添加到(有意义地)local
大小的信号处理程序中。在实际代码中,所有这些可能都以某种方式确定了范围,因此可能不需要额外的块。
请注意,Windows没有POSIX信号,Perl仅仿真一些非常基本的UNIX信号,以及Windows专用的SIGBREAK
。