2010-02-22 2 views
7

Ich habe einen Befehl, der in der Befehlszeile funktioniert. Es hat viele Argumente wie cmd --thing foo --stuff bar -a b input outputVerwenden von Python zum Ausführen anderer Programme

Ich möchte dies von Python ausführen und blockieren, bis es abgeschlossen ist. Da das Skript Dinge auf stdout und stderr druckt, möchte ich es dem Benutzer sofort gezeigt werden.

Was ist das richtige Modul dafür?

Ich habe versucht:


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

funktioniert dies sehr gut mit Ausnahme der stdout nicht bis zum Ende zurückgegeben.


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

diese druckt alle ausgegeben, wenn die cmd tatsächlich beendet ist.


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

dies nicht passiert die Parameter richtig irgendwie (ich habe das genaue Problem zu finden, nicht in der Lage gewesen, aber cmd meine Eingabe ablehnt). Wenn ich echo als den ersten Parameter setze, druckt es den Befehl aus, der tadellos funktioniert, wenn ich ihn direkt in das Terminal einfüge.


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

genau die gleichen wie oben.

+0

Behoben. Vielen Dank. –

Antwort

3

arbeiten Wenn Sie nicht brauchen, die Ausgabe in Ihrem Code zu verarbeiten, es dem Benutzer zu zeigen, nur als es geschieht (es von Ihrem Q nicht klar ist, und es scheint, dass die Art und Weise von den eigenen Selbst Antwort), einfachste ist:

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

dh nur vermeiden, jegliche Verwendung von Rohren - lassen stdout und stderr nur auf zeigen Das Terminal. Das sollte jedes Problem mit der Pufferung vermeiden. Sobald Sie Rohre in das Bild, Pufferung in der Regel ist ein Problem, wenn Sie die Ausgabe zeigen möchten, wie es passiert (Ich bin überrascht, Ihre Selbst-Antwort hat dieses Problem nicht ;-).

sowohl für und Erfassung zeigt, BTW, ich recomment immer pexpect (und wexpect auf Windows) genau um die Pufferung Problem zu umgehen.

+0

Wie immer, danke Alex. Es scheint, die 'subprocess.call()' puffert die Ausgabe des anderen Programms, das ist nicht das Verhalten, das normalerweise auf dem Terminal für dieses Programm passiert. Sollte ich nur eine 'proc = subprocess.Popen' und dann eine for-Schleife auf' proc.stdout' die Ausgabe drucken? –

+1

@Paul, es ist nicht "subprocess" die Pufferung - es ist die C-Runtime-Bibliothek des anderen Programms tut es, wenn es bemerkt, dass es zu einer Pipe statt einem Terminal geht (was Sie beobachten, ist überraschend, da stdout _is_ Terminal geht so die Pufferung sollte nicht passieren). 'pexpect' verwendet Pseudo-Terminals, um die Runtime-Bibliotheken des anderen Programms zu täuschen und sie so vom Puffern abzuhalten (' wexpect' unter Windows) - Ich habe sie viele, viele Male empfohlen, nach meinen anderen Antworten für ihre URLs zu suchen. –

7

Sie müssen jedes Feld einzeln angeben, dh. Teilen Sie die Optionen von ihren Argumenten.

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

sonst laufen Sie effektiv cmd wie diese

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

Um die Ausgabe in ein Rohr, die Sie brauchen, nennen es etwas anders

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' scheint die Ausgabe nicht zu drucken, da sie zurückgegeben wird. Kann ich das zulassen? –

+0

@Paul Tarjan: Das ist eine doppelte Frage. Bitte suchen Sie nach "[python] subprocess" und Sie erhalten Dutzende Antworten auf diese Frage. –

2

Würde nicht commands.getstatusoutput () Arbeit? Es wird deinen Status sofort ziemlich sicher zurückgeben.

+1

Es tut, aber sei gewarnt, dass es nur POSIX ist (kein Windows). – jathanism

1

Ein Kollege hat mir gezeigt, nur dies:

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

und es ist :)

+2

Sie sollten 'subprocess' anstelle von' popen' verwenden. Zum einen erspart es Ihnen, sich über das Ausbrechen von Parametern Sorgen zu machen. –

+1

Ein weiterer Grund: Python 2.6 'os.popen()' wird als veraltet zugunsten von 'subprocess' klassifiziert (siehe http://docs.python.org/library/os. html # os.popen). –