2010-02-22 5 views
7

Ho un comando che funziona alla grande sulla riga di comando. Ha molti argomenti come cmd --thing foo --stuff bar -a b input outputUtilizzo di python per eseguire altri programmi

Voglio eseguire questo da python e bloccare in attesa che si completi. Poiché lo script stampa le cose su stdout e stderr, voglio che venga mostrato immediatamente all'utente.

Qual è il modulo giusto per questo?

ho provato:


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

questa grande opera, tranne il stdout non viene restituito fino alla fine.


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

questa stampa tutti l'uscita quando il cmd è effettivamente finito.


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

questo non passa i parametri in modo corretto in qualche modo (non sono stato in grado di trovare l'esatto problema, ma cmd sta rifiutando il mio ingresso). Se metto echo come primo parametro, stampa il comando che funziona perfettamente quando lo incollo direttamente nel terminale.


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

esattamente lo stesso come sopra.

+0

Risolto. Grazie. –

risposta

3

Se non è necessario per elaborare l'output nel codice, solo per mostrare all'utente come accade (non è chiaro dal vostro Q, e sembra in questo modo dalla propria auto-risposta), più semplice è:

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

cioè, basta evitare qualsiasi utilizzo di tubi - diamo stdout e stderr solo mostrare su il terminale. Questo dovrebbe evitare qualsiasi problema con il buffering. Una volta inseriti i tubi nell'immagine, il buffering generalmente è un problema se si desidera mostrare l'output come accade (sono sorpreso che la propria auto-risposta non abbia quel problema ;-).

Per entrambi mostrando e cattura, BTW, ho sempre recomment pexpect (e wexpect su Windows) esattamente per aggirare il problema di buffering.

+0

Come sempre, grazie Alex. Sembra che 'subprocess.call()' buffer l'output dell'altro programma, che NON è il comportamento che di solito accade sul terminale per questo programma. Dovrei solo fare un 'proc = subprocess.Popen' e poi un ciclo for su' proc.stdout' per stampare l'output? –

+1

@Paul, non è "sottoprocesso" che fa il buffering - è la libreria di runtime C dell'altro programma che lo fa quando nota che sta andando a una pipe piuttosto che a un terminale (ciò che osservi è sorprendente dal momento che stdout sta andando al terminale così il buffering non dovrebbe accadere). 'pexpect' usa pseudo-terminali per ingannare le librerie di runtime degli altri programmi e quindi fermarli dal buffering (' wexpect' su Windows) - li ho raccomandati molte, molte volte, per cercare le mie altre risposte per i loro URL. –

7

Devi citare ciascun campo separatamente, es. dividere le opzioni dai loro argomenti.

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

altrimenti si sta effettivamente in esecuzione cmd come questo

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

Per ottenere l'output in un tubo è necessario chiamare in modo leggermente diverso

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

'sottoprocesso' non sembra stampare l'output mentre viene restituito. Posso farlo accadere? –

+0

@Paul Tarjan: Questa è una domanda doppia. Cerca per il sottoprocesso '" [python] "e riceverai dozzine di risposte a questa domanda. –

2

Non sarebbe commands.getstatusoutput () lavoro? Restituirà il tuo stato subito abbastanza sicuro.

+1

Lo fa, ma sii avvisato che è solo POSIX (no Windows). – jathanism

1

Un collega mi ha mostrato questo:

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

e si sta lavorando :)

+2

Si dovrebbe usare "sottoprocesso" preferibilmente a "popen". Per prima cosa ti risparmia preoccuparti dell'escursione dei parametri –

+1

Un altro motivo: Poichè Python 2.6 'os.popen()' è classificato come deprecato a favore di 'sottoprocesso' (vedi http://docs.python.org/library/os. html # os.popen). –