12
votes

Comment puis-je exécuter des commandes système Perl à l'arrière-plan?

#!/usr/bin/env perl
use warnings; use strict;
use 5.012;
use IPC::System::Simple qw(system);

system( 'xterm', '-geometry', '80x25-5-5', '-bg', 'green', '&' );

say "Hello";
say "World";
I tried this to run the xterm-command in the background, but it doesn't work:  
  No absolute path found for shell: & 
What would be the right way to make it work?

5 commentaires

Testé ici semble travailler pour moi. Qu'est-ce que vous essayez d'accomplir?


Est-il censé ouvrir le terminal puis imprimer Bonjour World dans le terminal?


Ou essayez-vous simplement de faire un appel asynchrone pour ouvrir le terminal?


Le "dit" ne sont que pour vérifier si la xterm fonctionne en arrière-plan.


Je l'ai compris (en utilisant un seul argument) il y a quelque temps, mais dans l'intervalle, je l'ai oublié (vient de la forme moyenne «moyenne»?). J'espère que je l'oublie pas une seconde fois.


4 Réponses :



20
votes

Perl's's System fonction a deux modes:

  1. Prendre une seule chaîne et le transmettre à la coquille de commande permettant de traiter des caractères spéciaux
  2. Prendre une liste de chaînes, exécutant le premier et passant les cordes restantes comme arguments

    Dans la première forme, vous devez faire attention à échapper aux personnages qui pourraient avoir une signification spéciale pour la coquille. La deuxième forme est généralement plus sûre puisque les arguments sont transmis directement au programme étant exécuté sans que la coque soit impliquée.

    Dans votre cas, vous semblez mélanger les deux formes. Le caractère & n'a la signification de "Démarrer ce programme en arrière-plan" si elle est transmise à la coquille. Dans votre programme, l'AMPersand est adopté en tant que 5ème argument de la commande Xterm.

    Comme Jakob Kruse a déclaré que la réponse simple est d'utiliser la forme unique du système système . Si l'un des arguments provenait d'une source non approuvée, vous devez utiliser citant ou échapper pour les sécuriser.

    Si vous préférez utiliser le formulaire multi-argument, vous devez appeler Fourche () puis utilisez probablement Exec () plutôt que système () .


1 commentaires

TLDR; système ("./ script.sh $ $ arg1 &"); au lieu de système ("./ script.sh", "$ arg1", "&");



13
votes

Notez que le formulaire de liste de système est spécifiquement là pour pas Traitez des caractères tels que & code> comme shell méta-caractères.

de Perlfaq8 's réponse à Comment puis-je lancer un processus en arrière-plan? p>


(contribué par Brian D Foy) P>

Il n'y a pas un seul moyen d'exécuter du code en arrière-plan, vous n'avez donc pas besoin d'attendre que la fin de votre programme ne passe à d'autres tâches. La gestion des processus dépend de votre système d'exploitation particulier et de nombreuses techniques sont en Perlipc. P>

Plusieurs modules CPAN peuvent être capables d'aider, notamment IPC :: Open2 ou IPC :: Open3 , IPC :: Run , Parallel :: Emploi , Parallel :: Forkmanager , poe , proc :: fond et win32 :: processus . Il existe de nombreux autres modules que vous pourriez utiliser, alors vérifiez également ces espaces de noms pour d'autres options. P>

Si vous êtes sur un système de type UNIX, vous pourrez peut-être vous éloigner avec un appel système où vous mettez un et à la fin de la commande: P>

unless ($pid = fork) {
    unless (fork) {
        exec "what you really wanna do";
        die "exec failed!";
    }
    exit 0;
}
waitpid($pid, 0);


0 commentaires

1
votes

Ce n'est pas purement une explication pour Perl. Le même problème est sous C et d'autres langues.

Comprend d'abord ce que la commande System fait:

  1. fourchettes
  2. Sous l'appel du processus enfant EXEC
  3. Le processus de parent attend que le processus d'enfant fourche a fini de finir

    Peu importe si vous passez plusieurs arguments ou un argument. La différence est, avec plusieurs arguments, la commande est exécutée directement. Avec un argument, la commande est enveloppée par la coque, et finalement exécutée comme suit: xxx

    lorsque vous passez une commande comme quelque_command Par1 Par2 & , Ensuite, entre l'interpréteur Perl et la commande est le processus sh ou BASH utilisé comme emballage, et elle attend Certain_command finition. Votre script attend l'interprète Shell, et aucun supplément PatitPID n'est nécessaire, car la fonction de Perl SYSTEM est-ce que vous êtes.

    Quand vous voulez Implémentez ce mécanisme directement dans votre script, vous devez:

    1. Utilisez la fonction fourchette . Voir l'exemple: http://users.telenet.be/bartl/classicperl/fork /all.html
    2. Sous l'état de l'enfance ( si ), utilisez la fonction exécutée . Votre utilisateur est similaire à System , voir le manuel. AVIS, EXEC provoque le programme de processus d'enfant / Contenu / Couverture de données par la commande exécutée.
    3. Sous la condition parent (si, les sorties de fourchettes avec non zéro), utilisez PIDPID, à l'aide de PID renvoyé par la fonction de fourche.

      C'est pourquoi vous pouvez exécuter le processus en arrière-plan. J'espère que c'est simple.

      L'exemple le plus simple: xxx


0 commentaires