2010-06-03 5 views
6

J'ai créé un script en Perl pour exécuter des programmes avec un timeout. Si le programme en cours d'exécution prend plus de temps que le script tue ce programme et renvoie le message "TIMEOUT".Problème avec fork exec kill lors de la redirection de la sortie en perl

Le script a fonctionné assez bien jusqu'à ce que je décide de rediriger la sortie du programme exécuté.

Lorsque stdout et stderr sont redirigés, le programme exécuté par le script n'est pas détruit car il a un pid différent de celui que j'ai reçu de fork.

Il semble que perl exécute un shell qui exécute mon programme dans le cas d'une redirection.

Je voudrais avoir la redirection de sortie mais être toujours capable de tuer le programme dans le cas d'un timeout.

Des idées sur comment je pourrais faire ça?

Un code simplifié de mon script est:

#!/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($?); 

Merci pour toute aide.

Répondre

11

Essayez de changer $cmd de

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

à

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

Le exec racontera la coquille qui obtient engendrée par perl pour se remplacer par very_long_program, plutôt que de courir very_long_program comme un enfant.

(La raison pour laquelle perl engendre un shell dans ce cas est que $cmd contient les caractères de redirection - et perl ne sait pas comment les gérer lui-même Une autre façon de résoudre le problème est de faire la redirection l'fork() mais avant d'appeler exec() - mais c'est un peu plus délicat, alors essayez le

+0

! Intelligent, propre et fonctionne. Tks. – Edu

2
première) solution exec

Une alternative consiste à rediriger STDOUT et STDERR après la fourche et exécutez la commande sans redirection:

open(STDOUT, ">", "out.txt") or die "Err: $!"; 
open(STDERR, ">&STDOUT"); 
exec("very_long_command"); 
die "Failed to exec very_long_command: $!"; 
Questions connexes