2010-02-22 15 views
7

Tengo un comando que funciona muy bien en la línea de comandos. Tiene muchos argumentos como cmd --thing foo --stuff bar -a b input outputUsando python para ejecutar otros programas

Quiero ejecutar esto desde python y bloquear esperando a que se complete. Como el script imprime cosas en stdout y stderr, quiero que se muestre inmediatamente al usuario.

¿Cuál es el módulo correcto para esto?

que he probado:


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

esto funciona muy bien, excepto el stdout no se devuelve hasta el final.


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

esta opción se imprime toda la salida cuando el cmd se acaba realmente.


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

esto no pasa correctamente los parámetros de alguna manera (no he sido capaz de encontrar el problema exacto, pero cmd está rechazando mi entrada). Si pongo echo como primer parámetro, imprime el comando que funciona perfectamente cuando lo pego directamente en el terminal.


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

exactamente el mismo que el anterior.

+0

Solucionado. Gracias. –

Respuesta

3

Si no es necesario para procesar la salida de su código, sólo para mostrarla al usuario como ocurre (que no está claro a partir de su Q, y parece que la manera de su propia auto-respuesta), más simple es:

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

es decir, simplemente evitar cualquier uso de tuberías - vamos a stdout y stderr sólo aparecen en la terminal. Eso debería evitar cualquier problema con el almacenamiento en búfer. Una vez que coloque los tubos en la imagen, el almacenamiento en memoria intermedia generalmente es un problema si desea mostrar el resultado tal como está (me sorprende que su auto-respuesta no tenga ese problema ;-).

Por tanto mostrando y captura, por cierto, yo siempre recomiendo pexpect (y wexpect en Windows) exactamente a evitar el problema de amortiguación.

+0

Como siempre, gracias Alex. Parece que el 'subprocess.call()' almacena en búfer la salida del otro programa, que NO es el comportamiento que generalmente ocurre en el terminal de este programa. ¿Debo hacer un 'proc = subprocess.Popen' y luego un ciclo for en' proc.stdout' imprimiendo la salida? –

+1

@Paul, no es 'subproceso' hacer el almacenamiento en búfer, es la biblioteca de tiempo de ejecución del otro programa que lo hace cuando se da cuenta de que va a una tubería en lugar de a un terminal (lo que observa es sorprendente ya que stdout _is_ va a la terminal para que el almacenamiento en búfer no debería suceder). 'pexpect' utiliza pseudo-terminales para engañar a las bibliotecas de tiempo de ejecución del otro programa y así detenerlos de almacenar en búfer (' wexpect' en Windows) - Los he recomendado muchas, muchas veces, pls buscar mis otras respuestas para sus URL. –

7

Debe citar cada campo por separado, es decir. divide las opciones de sus argumentos.

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

de lo contrario se están ejecutando efectivamente cmd como esto

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

Para obtener la salida en una tubería es necesario llamar a un poco diferente

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' no parece imprimir la salida tal como se devuelve. ¿Puedo hacer que eso suceda? –

+0

@Paul Tarjan: Esa es una pregunta duplicada. Por favor, busque '" [python] subprocess "' y obtendrá docenas de respuestas a esa pregunta. –

2

No sería commands.getstatusoutput () ¿trabajo? Te devolverá tu estado de inmediato, bastante seguro.

+1

Sí, pero tenga en cuenta que solo es POSIX (sin Windows). – jathanism

1

Un compañero de trabajo me mostró esto:

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

y está trabajando :)

+2

Debe usar 'subproceso' en lugar de' popen'. Por un lado, le ahorra preocuparse por los parámetros de escape –

+1

Otra razón: desde Python 2.6 'os.popen()' se clasifica como obsoleto a favor de 'subproceso' (ver http://docs.python.org/library/os. html # os.popen). –

Cuestiones relacionadas