首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >perl上的coreutils超时模拟

perl上的coreutils超时模拟
EN

Stack Overflow用户
提问于 2013-02-23 15:11:48
回答 2查看 509关注 0票数 4

我试图用perl替换超时(在centos5中需要)

在这里,脚本:

代码语言:javascript
复制
#!/usr/bin/perl
use strict;
my $pid=$$;
my $timeout=shift;
my @args=@ARGV;
eval {
        local $SIG{ALRM} = sub {
          print "Timed OUT!\n";
          exit 142;
          kill 9,$pid;
        };
        alarm($timeout);
        system(@args);
};
exit $?;

我在测试时发现:

这里全是精细的

代码语言:javascript
复制
time /tmp/timeout 3 sleep 6
Timed OUT!

real    0m3.007s
user    0m0.000s
sys     0m0.004s

,但这里都是坏的

代码语言:javascript
复制
time echo `/tmp/timeout 3 sleep 6`
Timed OUT!

real    0m6.009s
user    0m0.000s
sys     0m0.004s

在我的debian系统上,我用/usr/bin/timeout进行了测试

代码语言:javascript
复制
time echo `/usr/bin/timeout 3 sleep 6`


real    0m3.004s
user    0m0.000s
sys     0m0.000s

所以问题

  • 为什么perl脚本工作这么奇怪?
  • 在perl上是否有任何真正的工作方式让超时写与二进制超时一样工作?

请注意,我了解/usr/share/doc/bash-3.2/scripts/timeout,我还发现它的作用与我的perl方法相同。

另外,请注意,我无法在针对此脚本的服务器上安装CPAN中的模块

我尝试过使用exec(),但在这种情况下,它不处理sub中的信号。

UPD

使用@rhj的脚本(必须修复一点)

代码语言:javascript
复制
#!/usr/bin/perl
use strict;
use warnings;
my $PID=$$;
my $timeout=shift;
my @args=@ARGV;

my $pid = fork();
defined $pid or die "fork: $!";
$pid == 0 && exec(@args);

my $timed_out = 0;
$SIG{ALRM} = sub { $timed_out = 1; die; };
alarm $timeout;
eval { waitpid $pid, 0 };
alarm 0;
if ($timed_out) {
    print "Timed out!\n";
    kill 9, $pid;
    kill 9, $PID;
}
elsif ($@) {
    warn "error: $@\n";
}

它通过了上述测试,但在调用外部脚本时失败:

run_script

代码语言:javascript
复制
#!/bin/sh
sleep 6

test.sh

代码语言:javascript
复制
#!/bin/sh
a=`./timeout.pl 2 ./run_script.sh`

输出

代码语言:javascript
复制
$ time ./test.sh 

real    0m6.020s
user    0m0.004s
sys     0m0.008s
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-24 04:33:18

必须用IPC::Cmd制作;

代码语言:javascript
复制
#!/usr/bin/perl -w 
use strict;
use IPC::Cmd qw(run_forked);
my $timeout=shift;
my $stdout;
my $hashref = run_forked(@ARGV, { timeout => $timeout});
print $hashref->{'stdout'};
print STDERR $hashref->{'stderr'}; 
if ($hashref->{'timeout'}) {            
        print STDERR "Timed out!\n";
        exit 142;
}
exit $hashref->{'exit_code'};

我不得不使用rpmforge安装IPC::Cmd,这是件坏事。

票数 0
EN

Stack Overflow用户

发布于 2013-02-23 16:31:01

这个版本应该总是有效的:

代码语言:javascript
复制
#!/usr/bin/perl
use strict;
use warnings;
my $pid=$$;
my $timeout=shift;
my @args=@ARGV;

my $pid = fork();
defined $pid or die "fork: $!";
$pid == 0 && exec(@args);

my $timed_out = 0;
$SIG{ALRM} = sub { $timed_out = 1; die; };
alarm $timeout;
eval { waitpid $pid, 0 };
alarm 0;
if ($timed_out) {
    print "Timed out!\n";
    kill 9, $pid;
}
elsif ($@) {
    warn "error: $@\n";
}

不过,它不处理exec()调用中的错误。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15042004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档