【发布时间】:2013-02-23 15:11:48
【问题描述】:
我尝试使用 perl 替换超时(centos5 中需要)
这里是脚本:
#!/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 $?;
在测试时我发现:
一切正常
time /tmp/timeout 3 sleep 6
Timed OUT!
real 0m3.007s
user 0m0.000s
sys 0m0.004s
但这里都不好
time echo `/tmp/timeout 3 sleep 6`
Timed OUT!
real 0m6.009s
user 0m0.000s
sys 0m0.004s
在我使用 /usr/bin/timeout 测试的 debian 系统上:
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 的脚本(必须稍作修正)
#!/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
#!/bin/sh
sleep 6
test.sh
#!/bin/sh
a=`./timeout.pl 2 ./run_script.sh`
输出
$ time ./test.sh
real 0m6.020s
user 0m0.004s
sys 0m0.008s
【问题讨论】: