4

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

私がテストした私のdebianシステムで/usr/bin/timeout

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()たが、その場合はサブで信号を処理しません。

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
4

2 に答える 2

1

このバージョンは常に機能するはずです:

#!/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()呼び出しのエラーは処理しません。

于 2013-02-23T16:31:01.757 に答える
0

IPC::Cmdで作成する必要がありました。

#!/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をインストールしなければならなかったのは悪いことです。

于 2013-02-24T04:33:18.767 に答える