2010-06-03 12 views
6

Utworzono skrypt w perlu, aby uruchamiać programy z limitem czasu. Jeśli wykonywany program zabiera więcej czasu niż skrypt, ten program jest zwalniany i zwraca komunikat "TIMEOUT".Problem z kill exec kill podczas przekierowywania wyjścia w perl

Scenariusz działał całkiem dobrze, dopóki nie zdecydowałem się przekierować wyjścia z wykonanego programu.

Kiedy standardowe i stderr są przekierowywane, program wykonywany przez skrypt nie jest zabijany, ponieważ ma pid inny niż ten, który otrzymałem z widelca.

Wygląda na to, że perl wykonuje powłokę, która wykonuje mój program w przypadku przekierowania.

Chciałbym mieć przekierowanie wyjścia, ale nadal będę w stanie zabić program w przypadku przekroczenia limitu czasu.

Jakieś pomysły na to, w jaki sposób mogę to zrobić?

Uproszczony kod mojego skryptu jest:

#!/usr/bin/perl 

use strict; 
use warnings; 
use POSIX ":sys_wait_h"; 

my $timeout = 5; 
my $cmd = "very_long_program 1>&2 > out.txt"; 

my $pid = fork(); 
if($pid == 0) 
{ 
    exec($cmd) or print STDERR "Couldn't exec '$cmd': $!"; 
    exit(2); 
} 
my $time = 0; 
my $kid = waitpid($pid, WNOHANG); 
while ($kid == 0) 
{ 
    sleep(1); 
    $time ++; 
    $kid = waitpid($pid, WNOHANG); 
    print "Waited $time sec, result $kid\n"; 
    if ($timeout > 0 && $time > $timeout) 
    { 
     print "TIMEOUT!\n"; 
     #Kill process 
     kill 9, $pid; 
     exit(3); 
    } 
} 

if ($kid == -1) 
{ 
    print "Process did not exist\n"; 
    exit(4); 
} 
print "Process exited with return code $?\n"; 
exit($?); 

Dzięki za wszelką pomoc.

Odpowiedz

11

Spróbuj zmienić $cmd z

my $cmd = "very_long_program 1>&2 > out.txt"; 

do

my $cmd = "exec very_long_program 1>&2 > out.txt"; 

exec powie powłokę, która pobiera zrodził przez Perl wymienić się z very_long_program, zamiast prowadzenia very_long_program jako dziecko.

(Powód w tym przypadku wywołuje powłokę, ponieważ $cmd zawiera znaki przekierowania - a perl nie wie, jak sobie z nimi radzić. Alternatywnym sposobem rozwiązania problemu jest wykonanie przekierowania w samym perlu po fork() ale przed wywołaniem exec() - ale to jest nieco trudniejsze, więc spróbuj exec obejścia pierwsze)

+0

! Sprytnie, czysto i działa. Tks. – Edu

2

alternatywą jest przekierowanie STDOUT i stderr po widelec i uruchomić polecenie bez przekierowania:

open(STDOUT, ">", "out.txt") or die "Err: $!"; 
open(STDERR, ">&STDOUT"); 
exec("very_long_command"); 
die "Failed to exec very_long_command: $!"; 
Powiązane problemy