Windows和Linux中的Perl超时命令 [英] Perl timeout command in windows and linux

查看:210
本文介绍了Windows和Linux中的Perl超时命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个Perl脚本,该脚本需要在将运行进程的Windows和linux中工作,如果花费的时间太长则将其超时,并假设退出超时则返回退出代码,并假设exitcode为零时返回stdout而且没有超时.我不需要STDIN或STDERR.我尝试使用IPC::run,但无法使其正常工作.

I'm writing a perl script that needs to work in windows and linux that will run a process, timeout if it takes too long, return the exit code assuming it didn't timeout, and return stdout assuming the exitcode was zero and it didn't timeout. I don't need STDIN or STDERR. I've tried to use IPC::run but couldn't get it to work.

与我最接近的是IPC::Open3waitpid($pid, WNOHANG).但是我遇到了障碍.我在Windows和Linux上看到了不同的结果.在下面的代码中,我给open3一个将失败的命令(ping没有任何参数-z).在linux上,代码立即返回负退出代码.在Windows上,命令超时.在Windows命令行上运行ping google.com -z会立即返回,告诉我没有这样的参数.为什么``waitpid''返回零?

The closest I got is with IPC::Open3 and waitpid($pid, WNOHANG). But I've hit a snag. I'm seeing different results on windows and linux. In the code below I give open3 a command that will fail (ping doesn't have any argument -z). On linux the code immediately returns a negative exit code. On windows the command times out. Running ping google.com -z on the windows command line immediately returns telling me there is no such argument. Why does ``waitpid` return a zero?

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便携式.我的debian机器安装了perl 5.24.

Other solutions are welcome. The only reason I use waitpid with nohang is to kill the process if it takes too long. I dont have any other processing I need to do in the meantime. I'm using windows 10 strawberry perl 5.28 portable on windows. My debian machine has perl 5.24.

推荐答案

IPC :: Run 支持各种超时和计时器,在Win32上也可以使用.

The IPC::Run has support for various timeouts and timers, which should also work on 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.还有其他计时器,其行为更加微妙和易于管理.请参阅文档.

The timeout throws an exception, thus the eval. There are other timers, with behavior which is more subtle and manageable. Please see documentation.

如果捕获的异常不是由IPC::Run的计时器引起的,则重新引发异常-根据消息中打印的系统上模块的版本判断,该字符串以 IPC开头:运行:超时.请检查系统上的内容.

The exception is re-thrown if the one caught isn't caused by IPC::Run's timer -- judged by what the module's version on my system prints in the message, a string starting with IPC::Run: timeout. Please check what that is on your system.

我认为,尽管某些事情在Windows上不起作用,但计时器应该可以.我现在无法测试.

While some things don't work on Windows the timers should, I think. I can't test right now.

据报道,尽管上面的方法有效,但使用了更有意义的命令,SIGBREAK (21)会在超时时发出,一旦得到处理,该过程就会继续进行.

It's reported that, while the above works, with a more meaningful command in place the SIGBREAK (21) is emitted at timeout, and once it is handled the process stays around.

在这种情况下,请在处理程序中手动将其终止

In this case terminate it manually in the handler

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.

In order to be able to use the module's kill_kill here I first create the harness, which is then available when the handler is installed, and on which kill_kill can be called when it fires.

另一种方法是找到进程ID(使用 Win32 :: Process TASKKILL.请参阅这篇文章(下半部分).

Another way would be to find the process ID (with Win32::Process::Info or Win32::Process::List), and terminate it with kill, or Win32::Process, or TASKKILL. See this post (second half).

仅在local -ize信号处理程序中添加一个块.在实际代码中,所有这些可能都以某种方式确定了范围,因此可能不需要额外的块.

A block is added only to local-ize the signal handler. In real code all this is likely scoped in some way so an extra block may not be needed.

请注意,Windows没有POSIX信号,并且Perl仅仿真一些非常基本的UNIX信号,以及Windows特定的SIGBREAK.

Note that Windows doesn't have POSIX signals and that Perl emulates only a few very basic UNIX signals, along with the Windows-specific SIGBREAK.

这篇关于Windows和Linux中的Perl超时命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆