windows和linux中的Perl超时命令

windows和linux中的Perl超时命令,perl,timeout,waitpid,Perl,Timeout,Waitpid,我正在编写一个perl脚本,该脚本需要在windows和linux中运行,该脚本将运行一个进程,如果需要的时间太长,则超时,如果没有超时,则返回退出代码,如果exitcode为零且没有超时,则返回stdout。我不需要STDIN或STDERR。我尝试使用IPC::run,但无法使其正常工作 我得到的最接近的是IPC::Open3和waitpid($pid,WNOHANG)。但我遇到了一个障碍。我在windows和linux上看到了不同的结果。在下面的代码中,我给了open3一个将失败的命令(pi

我正在编写一个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";
}
使用严格;
使用警告;
使用POSIX“:sys_wait_h”;
使用IPC::Open3;
我的$inFH;
我的$outph;
my@cmd=(“ping”,“google.com”,“-z”);
my$pid=open3($inFH,$outph,0,@cmd);
我的$counter=0;
我的$waitret;
我的$exitcode;
做{
$counter++;
$waitret=waitpid($pid,WNOHANG);
$exitcode=$?;
}而(!$waitret和($counter<4_000_000));
如果($counter>=4_000_000){
打印“命令超时\n”;
杀戮(9美元);
}否则{
打印“退出代码:$exitcode\n”;
}
欢迎其他解决办法。我将waitpid与nohang一起使用的唯一原因是,如果需要的时间太长,就会终止进程。在此期间,我不需要做任何其他处理。 我正在windows上使用Windows10和Perl5.28便携版。我的debian机器有perl 5.24。

支持各种,也可以在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:timeout开头的字符串。请检查您的系统上有什么

虽然有些东西在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\u kill
在这里,我首先创建了线束,当安装处理程序时可以使用线束,当它触发时可以在线束上调用
kill\u kill

另一种方法是查找进程ID(带或), 并用
kill
TASKKILL
终止它。见(下半部分)

仅将块添加到
本地
-使信号处理程序变大。在实际代码中,所有这些都可能以某种方式限定范围,因此可能不需要额外的块


请注意,Windows没有POSIX信号,Perl只模拟一些非常基本的UNIX信号,以及Windows特有的
SIGBREAK

请注意,它有一个超时参数,因此可以避免繁忙的等待循环。另请参阅使用IPC::Cmd和runmyscript似乎耐心地等待进程结束,然后通知我是否违反了超时。使用“ping google.com/t”运行会导致运行挂起,等待ping停止,即使我已将超时设置为4。在linux中,它似乎按预期工作。不幸的是,Windows没有真正的分叉,所以它是通过ithreads模拟的。Windows也不支持POSIX信令。这可能就是你看到不同行为的原因。这是有效的。。。。奇怪的是,如果我只是使用你的代码并用ping google.com/t替换sleep 20,那么我会在提示符上得到以下消息:“终止信号SIGBREAK(21)”,我的脚本就会完全死掉。如果它输入了$SIG{BREAK}的catch,那么我会在我输入的超时时间看到我的SIG{BREAK}消息。。。。但是脚本仍然在ping上挂起至少20秒。。。。也许它想以某种方式优雅地杀死这个命令?我能让它更有力吗?@serpixo-heh。。。在发布之前我已经搜索过了(现在无法测试Win),并且有一些参考文献提到了
SIGBREAK
——但只是关于模块安装的。还有其他方法来计算时间,还有文档链接部分的完整示例。你能看看那里吗?我现在无法在Windows上进行测试:(@serpixo如果你能捕获它,那么你几乎可以确定你可以操纵它。我会尝试以下方法:在“信号”处理程序中使用该命令(在Win32上没有真正的信号,但只模拟基本信号)。当然,最好不要这样做;尝试其他方法给docs的时间。谢谢zdim,如果我找到更好的解决方案,我会给你回复。现在你的解决方案最适合我的需要。希望我能找到一个更…及时的解决方案。@serpixo好的。我稍后会看更多内容并尝试在Windows上测试。如果仍然停留在通过处理程序手动终止进程,请让我知道,我可以dd代码。