5025 votes

Appeler une commande externe en Python

<p>Comment puis-je appeler une commande externe (comme si j’avais tapé au shell Unix ou invite de commande Windows) partir d’un script Python ?</p>

4833voto

David Cournapeau Points 21956

Regardez le sous-processus module dans la stdlib:

from subprocess import call
call(["ls", "-l"])

L'avantage de la sous-processus vs système est qu'il est plus souple (vous pouvez obtenir le stdout, stderr, "le vrai" code d'état, une meilleure gestion des erreurs, etc...). Je pense que les os.le système est obsolète, trop, ou sera:

http://docs.python.org/library/subprocess.html#replacing-older-functions-with-the-subprocess-module

Pour rapide/sale/une fois les scripts, os.system est suffisant, mais.

3035voto

Eli Courtwright Points 53071

Voici un résumé des moyens de faire appel à des programmes externes et les avantages et les inconvénients de chacun:

  1. os.system("some_command with args") passe la commande et les arguments de votre shell du système. C'est agréable car vous pouvez réellement exécuter plusieurs commandes à la fois de cette manière et jeu de tuyaux et d'entrée/sortie de la redirection. Par exemple,
    os.system("some_command < input_file | another_command > output_file")
    Cependant, si cela est pratique, vous devez manuellement la poignée de l'échappement de la coquille des caractères tels que des espaces, etc. D'autre part, cela vous permet également d'exécuter des commandes qui sont tout simplement des commandes shell et pas vraiment de programmes externes.
    voir la documentation

  2. stream = os.popen("some_command with args") va faire la même chose que os.system , sauf qu'il vous donne un fichier objet en forme que vous pouvez utiliser pour l'accès d'entrée/sortie standard de ce processus. Il y a 3 autres variantes de popen que tous gérer les i/o de façon légèrement différente. Si vous passez tout comme une chaîne de caractères, votre commande est transmise à la coquille; si vous passer comme une liste, alors vous n'avez pas besoin de s'inquiéter au sujet d'échapper à quoi que ce soit.
    voir la documentation

  3. L' Popen classe de l' subprocess module. C'est conçu comme un remplacement pour os.popen , mais a l'inconvénient d'être un peu plus compliquée par la vertu de l'être exhaustive. Par exemple, vous dirais

    print subprocess.Popen("echo Hello World", shell=True, stdout=PIPE).stdout.read()
    

    au lieu de

    print os.popen("echo Hello World").read()
    

    mais c'est sympa d'avoir toutes les options existe en une seule unifiée de la classe au lieu de 4 différents popen fonctions.
    voir la documentation

  4. L' call fonction de l' subprocess module. C'est fondamentalement juste comme l' Popen de la classe et prend toutes les mêmes arguments, mais simplement il attend jusqu'à ce que la commande se termine et vous donne le code de retour. Par exemple:

    return_code = subprocess.call("echo Hello World", shell=True)  
    

    voir la documentation

  5. Le module os a également toutes les fork/exec/spawn fonctions que vous auriez dans un programme en C, mais je ne recommande pas de les utiliser directement.

L' subprocess module doit probablement être ce que vous utilisez.

Enfin, s'il vous plaît être conscient que, pour toutes les méthodes dans lesquelles vous pouvez passer la dernière commande exécutée par le shell comme une chaîne de caractères et vous êtes responsable de prendre la fuite il y a de graves répercussions sur la sécurité si une partie quelconque de la chaîne que vous transmettez ne peut pas être digne de confiance (par exemple, si un utilisateur entre dans certains/une partie de la chaîne). En cas de doute, n'utiliser ces méthodes avec des constantes. Pour vous donner une idée de considérer les implications de ce code

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

et imaginez que l'utilisateur entre "ma maman ne m'aime && rm -rf /".

372voto

EmmEff Points 1789
<p>J’utilise généralement :<pre><code></code></pre><p>Vous êtes libre de faire ce que vous voulez avec les données de stdout dans le tuyau. En fait, vous pouvez simplement omettre ces paramètres (stdout = et stderr =) et il va se comporter comme os.system().</p></p>

239voto

newtover Points 12301

Des indications sur la façon de détacher l'enfant de processus à partir de l'appel un (en commençant le processus de l'enfant en arrière-plan).

Supposons que vous voulez commencer une longue tâche à partir d'un script CGI, qui est le processus de l'enfant devrait vivre plus longtemps que le script CGI processus d'exécution.

L'exemple classique de la sous-processus module docs est:

import subprocess
import sys

# some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # call subprocess

# some more code here

L'idée ici est que vous ne voulez pas attendre dans la ligne de l'appel de sous-processus " jusqu'à la longtask.py est fini. Mais il n'est pas clair ce qui se passe après la ligne " code plus ici de l'exemple.

Ma plate-forme cible a été freebsd, mais le développement a été sur windows, j'ai donc rencontré le problème sur windows en premier.

Sur windows (win xp), le processus parent ne finira pas jusqu'à ce que le longtask.py a l'issue de ses travaux. Ce n'est pas ce que vous voulez dans CGI-script. Le problème n'est pas spécifique à Python, PHP communauté, les problèmes sont les mêmes.

La solution est de passer DETACHED_PROCESS drapeau de la sous-fonction CreateProcess à gagner de l'API. Si vous avez installé pywin32 vous pouvez importer le drapeau de la win32process module, sinon vous devez définir vous-même:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

Sur freebsd, nous avons un autre problème: lorsque le processus parent est fini, il termine le processus enfant. Et ce n'est pas ce que vous voulez dans CGI-script. Certaines expériences ont montré que le problème semblait être dans le partage de sys.la sortie standard stdout. Et la solution de travail était le suivant:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

Je n'ai pas vérifié le code sur d'autres plates-formes et ne connais pas les raisons du comportement sur freebsd. Si quelqu'un sait, merci de partager vos idées. Googler sur le démarrage de processus d'arrière-plan en Python ne pas jeter toute la lumière encore.

156voto

SirWart Points 627
<p>Je conseille d’utiliser le module sous-processus au lieu de os.system parce qu’il bombarder s’échapper pour vous et est donc beaucoup plus sûr : <a href="http://docs.python.org/library/subprocess.html" rel="nofollow">http://docs.python.org/library/subprocess.html</a><pre><code></code></pre></p>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X