2010-03-18 9 views
2

Je suis débutant en Perl et j'ai de la difficulté à utiliser l'appel "system". Voici un petit morceau de code où je tente d'exécuter 2 commandes shell:Pourquoi l'appel système Perl échoue-t-il avec un point?

# First command is : 
# dot -Tpng $dottmpfile > $pngfile 
# Second command is : 
# rm $dottmpfile 

if (!($pngfile eq "")) { 
    my @args = ("dot", "-Tpng", $dottmpfile, " > ", $pngfile); 
    system (join (' ' , @args)) 
    or die "system @args failed : $!"; 

    unlink $dottmpfile; 
} 

EDIT: Voici mon code, et je encore obtenir une erreur:

system dot -Tpng toto.dot > toto.png failed : Inappropriate ioctl for device at /home/claferri/bin/fractal.pl line 79. 

Je l'ai utilisé system pour produire ce morceau de code.

+2

Si vous voulez juste ça va rapidement, fusionnez la ligne entière en une seule chaîne et placez-la en arrière: $ result = \ 'dot -Tpng $ dottmpfile> $ pngfile \'; –

+1

voir ici: http://stackoverflow.com/questions/2461472/how-can-i-run-an-external-command-and-capture-its-output-in-perl/2461664#2461664. Aussi, pour supprimer des fichiers, utilisez 'unlink()'.pas besoin d'appeler le système 'rm' – ghostdog74

+2

Vous devriez utiliser $! plutôt que $? - Cela vous donnera le message d'erreur plutôt que le code d'erreur, et cela vous dira presque toujours ce qui s'est mal passé. –

Répondre

3

Regarder perldoc -f system, Note:

S'il y a plus d'un argument dans LIST, ou si LIST est un tableau avec plus d'une valeur, commence le programme donné par le premier élément de la liste avec arguments donnés par le reste de la liste. S'il n'y a qu'un seul argument scalaire, l'argument est vérifié pour métacaractères, et s'il y a lieu, l'argument entier est passé à la shell de commande du système pour l'analyse syntaxique

Vous invoquez system LIST de sorte que le > finit par être passé à dot au lieu d'être interprété par le shell.

Je vous recommande de continuer à utiliser system LIST car c'est un peu plus sûr que de tout passer à travers la coque. Selon les documents, vous pouvez spécifier le fichier de sortie en utilisant l'option -o à dot, alors faites-le.

Si vous voulez vraiment les points sur votre i s et croisez t s (jeu de mots ne sont pas destinés), vous pouvez utiliser:

if (defined $pngfile and $pngfile ne '') { 
    my @args = (dot => '-Tpng', $dottmpfile, "-o$pngfile"); 
    if (system @args) { 
     warn "'system @args' failed\n"; 
     my $reason = $?; 
     if ($reason == -1) { 
      die "Failed to execute: $!"; 
     } 
     elsif ($reason & 0x7f) { 
      die sprintf(
       'child died with signal %d, %s coredump', 
       ($reason & 0x7f), 
       ($reason & 0x80) ? 'with' : 'without' 
      ); 
     } 
     else { 
      die sprintf('child exited with value %d', $reason >> 8); 
     } 
    } 
    warn "'system @args' executed successfully\n"; 
    unlink $dottmpfile; 
} 
+0

Je ne comprends pas ce que vous me recommandez? Ou vouliez-vous dire "would not"? Alors quoi d'autre dois-je utiliser? Mon besoin est juste de traiter la commande dot, et obtenir sa sortie dans le fichier $ pngfile (utiliser '>' est mon premier reflex car c'est comme ça que je le fais dans bash, mais il y a peut-être de meilleures façons de le faire en perl – claf

+1

@claferri Je vous recommande de conserver le formulaire 'system LIST' et de spécifier le fichier de sortie en utilisant l'option' -o' plutôt que l'opérateur de redirection de shell '>'. –

+0

Cela semble être beaucoup plus clair maintenant :) thx! – claf

3

Vous utilisez > pour indiquer au shell de rediriger la sortie vers un fichier en appelant system LIST, vous contournant le shell. Par conséquent, vous pouvez utiliser:

system (join (' ' , @args)); 

ou

system "@args"; 
+0

@pavun Il existe une différence cruciale entre le passage d'une liste à une chaîne unique à 'system' (ou' qx'). –

+0

Il existe, et le fait que ce soit une liste et non une chaîne est ce qui empêche le code de claferri de fonctionner, puisqu'il repose sur des fonctionnalités du shell. – hobbs

+0

@hobbs: donc si je comprends ce que vous dites, le problème est qu'il n'y a pas d'espaces dans la liste et la fonction de jointure fait une chaîne avec l'espace séparé d'une liste? – claf

-1

est l'exécutable "point" dans le PATH? A-t-il des autorisations exécutables? Quelle erreur spécifique obtenez-vous avec ce code?

Il semble que c'est correct selon perldoc -f system.

+0

Bien sûr, point est un paquet debian bien connu, il n'y a donc aucun moyen que cela soit la source du problème. – claf

+0

ummmmmm ... Je n'ai jamais entendu parler de ça^_ ^> ... Merci pour l'info – darkturo

+0

c'est un outil graphique (package: graphviz) qui est utilisé pour créer une image graphique (fichier png par exemple) à partir du fichier texte décrivant un graphique, très utile pour moi;) – claf

1

system renvoie 0 et non nulle sur "échec". Il est contraire à la façon dont la plupart de ces idiomes regarder et un peu contre-intuitif, mais avec system appels, vous devez utiliser une expression comme:

system($command) and warn "system $command: failed $?\n"; # and not or 

ou

if (system($command) != 0) { ... handle error ... }