2010-02-22 6 views
7

J'ai une commande qui marche bien sur la ligne de commande. Il a beaucoup d'arguments comme cmd --thing foo --stuff bar -a b input outputUtiliser python pour exécuter d'autres programmes

Je veux lancer ceci à partir de python et bloque l'attente pour qu'il se termine. Comme le script imprime les choses à stdout et stderr je veux qu'il soit immédiatement montré à l'utilisateur.

Quel est le bon module pour cela?

J'ai essayé:


import commands 
output = commands.getoutput("cmd --thing foo --stuff bar -a b input output") 
print output 

Cela fonctionne très bien, sauf la stdout n'est pas retourné jusqu'à la fin.


import os 
os.system("cmd --thing foo --stuff bar -a b input output") 

cette imprime toute la sortie lorsque le cmd est effectivement terminé.


import subprocess 
subprocess.call(["cmd", "--thing foo", "--stuff bar", "-a b", "input", "output"]) 

cela ne passe pas correctement les paramètres d'une certaine manière (je ne l'ai pas été en mesure de trouver le problème exact, mais cmd rejette mon entrée). Si je mets echo comme premier paramètre, il imprime la commande qui fonctionne parfaitement lorsque je le colle directement dans le terminal.


import subprocess 
subprocess.call("cmd --thing foo --stuff bar -a b input output") 

exactement la même chose que ci-dessus.

+0

Fixé. Je vous remercie. –

Répondre

3

Si vous n'avez pas besoin de traiter la sortie dans votre code, pour montrer à l'utilisateur que il arrive (on ne sait pas à partir de votre Q, et il semble que moyen de votre propre auto-réponse), est la plus simple:

rc = subprocess.call(
    ["cmd", "--thing", "foo", "--stuff", "bar", 
    "-a", "b", "input", "output"]) 
print "Return code was", rc 

-à-dire, il faut juste éviter toute utilisation de tuyaux - laissez stdout et stderr juste montrer sur le terminal. Cela devrait éviter tout problème de mise en mémoire tampon. Une fois que vous mettez des tuyaux dans l'image, la mise en mémoire tampon est généralement un problème si vous voulez montrer la sortie comme il arrive (je suis surpris que votre réponse personnelle n'a pas ce problème ;-).

Pour les deux montrant et capture, BTW, j'ai toujours recomment pexpect (et wexpect sous Windows) exactement à contourner le problème de la mise en mémoire tampon.

+0

Comme toujours, merci Alex. Il semble que 'subprocess.call()' tamponne la sortie de l'autre programme, ce qui n'est PAS le comportement qui se produit habituellement sur le terminal pour ce programme. Devrais-je faire un 'proc = subprocess.Popen' et ensuite une boucle for sur' proc.stdout' pour imprimer la sortie? –

+1

@Paul, ce n'est pas 'subprocess' qui fait la mise en mémoire tampon - c'est la bibliothèque C de l'autre programme qui le fait quand il remarque qu'il va à un tuyau plutôt qu'à un terminal (ce que vous observez est surprenant ne devrait pas arriver). 'pexpect' utilise des pseudo-terminaux pour tromper les bibliothèques d'exécution de l'autre programme et ainsi les empêcher de mettre en mémoire tampon (' wexpect' sous Windows) - je leur ai recommandé de nombreuses fois de chercher mes autres réponses pour leurs URLs. –

7

Vous devez citer chaque champ séparément, c.-à-d. séparer les options de leurs arguments.

import subprocess 
output = subprocess.call(["cmd", "--thing", "foo", "--stuff", "bar", "-a", "b", "input", "output"]) 

sinon vous sont effectivement en cours d'exécution cmd comme celui-ci

$ cmd --thing\ foo --stuff\ bar -a\ b input output 

Pour obtenir la sortie dans un tuyau, vous devez appeler un peu différemment

import subprocess 
output = subprocess.Popen(["cmd", "--thing", "foo", "--stuff", "bar", "-a", "b", "input", "output"],stdout=subprocess.PIPE) 
output.stdout # <open file '<fdopen>', mode 'rb'> 
+0

'subprocess' ne semble pas imprimer la sortie comme elle est retournée. Puis-je y arriver? –

+0

@Paul Tarjan: C'est une question en double. Veuillez rechercher "" [python] sous-processus "' et vous obtiendrez des dizaines de réponses à cette question. –

2

Ne serait-commands.getstatusoutput () travail? Il va retourner votre statut tout de suite assez sûr.

+1

C'est le cas, mais soyez averti que c'est POSIX seulement (pas de Windows). – jathanism

1

Un collègue de travail m'a juste montré ceci:

import os 
import sys 
for line in os.popen("cmd --thing foo --stuff bar -a b input output", "r"): 
    print line 
    sys.stdout.flush() 

et il fonctionne :)

+2

Vous devriez utiliser 'subprocess' de préférence' popen'. D'une part cela vous évite de vous soucier des paramètres d'échappement –

+1

Une autre raison: Depuis Python 2.6 'os.popen()' est classé comme obsolète au profit de 'subprocess' (voir http://docs.python.org/library/os. html # os.popen). –

Questions connexes