2009-02-17 13 views
4

Perl's system() lance un processus, mais interrompt la relation parent/enfant?Pourquoi le processus ne démarre-t-il pas avec le système de Perl()?

test.pl:

use POSIX; 

system("./test.sh &"); 

my $pid = `ps -C test.sh -o pid=`; 

print "pid: -$pid-\n"; 

waitpid($pid, 0); 

test.sh:

while true 
do 
    sleep 1 
done 

Quand je lance test.pl, il trouve et imprime une pid correcte de test.sh. Mais waitpid() renvoie -1 et test.pl se ferme. Après que test.pl existe, test.sh est toujours en cours d'exécution.

Il ressemble à test.sh est pas un enfant de test.pl, qui brise waitpid(). Pourquoi cela se produit-il et comment faire fonctionner system()? Est-ce parce que Perl efface automatiquement les enfants? Si oui, comment puis-je résoudre une tâche générale d'attente sur un enfant explicitement?

Mise à jour:

réponses ci-dessous suggèrent avec fork/exec. Le problème initial est le suivant:

  1. À partir d'un script Perl, exécutez un utilitaire de ligne de commande qui démarre un service. L'utilitaire quitte mais le service reste.

  2. après un certain temps, constater que pid de service et attendre là-dessus.

fork/exec ne résout pas cela, même si cela éclaircit la question.

+0

Pourquoi fais-tu ça? – jrockway

+0

@Liudvikas réponse est exactement exact. Si vous voulez waitpid, utilisez fork et exec, pas de système. –

Répondre

15

Le processus de test.sh n'est pas votre processus d'enfant. Le system() a forké un shell (qui est votre enfant), ce shell a forké un enfant qui a exécuté le programme test.sh. Le shell qui était votre enfant est sorti.

+0

Juste curieux: est-ce que waitpid sort parce que le pid donné n'est pas un de ses enfants? –

+1

Oui. La valeur de retour de -1 indique juste cela: aucun processus enfant de ce type – innaM

5

Pour expliquer plus en détail la réponse de Liudvikas -

system("./test.sh &") 
| 
|--> (P) /bin/sh (to run test.sh) 
     | 
     |--> (P) test.sh & (still running) 

(P) - process 

Après fork'ing et l'exécution du script test.sh le shell/bin/sh, qui était l'enfant de l'appel système Perl, les sorties et ainsi vous obtenir une valeur de retour -1 de waitpid().

6

Qu'est-ce que vous voulez sans doute faire est quelque chose comme ceci:

my $pid = fork || exec './test.sh'; 
print "pid: -$pid-\n"; 
waitpid($pid, 0); 

Bien que depuis le script shell est dans une boucle infinie, il attendra toujours.

6

En général, vous devez fourche manuellement et exec si vous ne voulez pas Perl pour aider vous sortir. Il est difficile de déterminer exactement ce que vous faites, mais je pense que vous voulez ceci:

my $pid = fork; 
unless($pid){ 
    # child; 
    exec(qw/sh test.sh/); 
} 

# parent 
... 
waitpid $pid, 0; 

Personnellement, je préfère laisser AnyEvent garder les enfants:

my $done = AnyEvent->condvar; 

my $pid = fork; 

unless($pid) { ... } 

my $w = AnyEvent->child (
    pid => $pid, 
    cb => sub { 
     my ($pid, $status) = @_; 
     warn "pid $pid exited with status $status"; 
     $done->send; 
    }, 
); 

$done->recv; # control resumes here when child exits 

Ou, plus généralement: http://github.com/jrockway/anyevent-subprocess/tree/master

+0

Je n'ai jamais vu AnyEvent auparavant. Est-ce une partie standard de la plupart des distributions, ou ai-je besoin de le télécharger du CPAN? –

+0

CPAN. (POE est une autre option.) – jrockway