La risposta a questa domanda dipende dalla versione di Python che stai utilizzando. L'approccio più semplice è utilizzare la subprocess.check_output
funzione:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
esegue un singolo programma che accetta solo argomenti come input. 1 Restituisce il risultato esattamente come stampato stdout
. Se è necessario scrivere input su stdin
, andare avanti alle sezioni run
o Popen
. Se si desidera eseguire comandi di shell complessi, vedere la nota shell=True
alla fine di questa risposta.
La check_output
funzione funziona su quasi tutte le versioni di Python ancora ampiamente utilizzate (2.7+). 2 Ma per le versioni più recenti, non è più l'approccio consigliato.
Versioni moderne di Python (3.5 o successive): run
Se si utilizza Python 3.5 o versioni successive e non è necessaria la compatibilità con le versioni precedenti , si consiglia la nuova run
funzione . Fornisce un'API di alto livello molto generale per il subprocess
modulo. Per acquisire l'output di un programma, passare il subprocess.PIPE
flag stdout
all'argomento della parola chiave. Quindi accedere stdout
all'attributo CompletedProcess
dell'oggetto restituito :
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Il valore restituito è un bytes
oggetto, quindi se si desidera una stringa corretta, è necessario decode
. Supponendo che il processo chiamato restituisca una stringa con codifica UTF-8:
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Tutto questo può essere compresso in un unico liner:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Se si desidera passare l'input al processo stdin
, passare un bytes
oggetto input
all'argomento della parola chiave:
>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
È possibile acquisire errori passando stderr=subprocess.PIPE
(acquisisci in result.stderr
) o stderr=subprocess.STDOUT
(acquisisci result.stdout
insieme all'output normale). Quando la sicurezza non è un problema, è anche possibile eseguire comandi di shell più complessi passando shell=True
come descritto nelle note di seguito.
Questo aggiunge solo un po 'di complessità, rispetto al vecchio modo di fare le cose. Ma penso che valga la pena pagare: ora puoi fare quasi tutto ciò che devi fare con la run
sola funzione.
Versioni precedenti di Python (2.7-3.4): check_output
Se stai usando una versione precedente di Python o hai bisogno di una modesta compatibilità con le versioni precedenti, puoi probabilmente usare la check_output
funzione come brevemente descritto sopra. È disponibile da Python 2.7.
subprocess.check_output(*popenargs, **kwargs)
Prende gli stessi argomenti di Popen
(vedi sotto) e restituisce una stringa contenente l'output del programma. L'inizio di questa risposta ha un esempio di utilizzo più dettagliato. In Python 3.5 e versioni successive, check_output
equivale a eseguire run
con check=True
e stdout=PIPE
e restituire solo l' stdout
attributo.
Puoi passare stderr=subprocess.STDOUT
per assicurarti che i messaggi di errore siano inclusi nell'output restituito, ma in alcune versioni di Python il passaggio stderr=subprocess.PIPE
a check_output
può causare deadlock . Quando la sicurezza non è un problema, è anche possibile eseguire comandi di shell più complessi passando shell=True
come descritto nelle note di seguito.
Se è necessario eseguire il pipe stderr
o passare l'input al processo, check_output
non sarà all'altezza dell'attività. Vedi gli Popen
esempi seguenti in quel caso.
Applicazioni complesse e versioni legacy di Python (2.6 e precedenti): Popen
Se hai bisogno di una profonda compatibilità con le versioni precedenti o se hai bisogno di funzionalità più sofisticate di quelle check_output
fornite, dovrai lavorare direttamente con gli Popen
oggetti, che incapsulano l'API di basso livello per i sottoprocessi.
Il Popen
costruttore accetta un singolo comando senza argomenti o un elenco contenente un comando come primo elemento, seguito da un numero qualsiasi di argomenti, ciascuno come elemento separato nell'elenco. shlex.split
può aiutare ad analizzare le stringhe in elenchi formattati in modo appropriato. Popen
gli oggetti accettano anche una serie di argomenti diversi per la gestione dell'IO processo e la configurazione di basso livello.
Per inviare input e acquisire output, communicate
è quasi sempre il metodo preferito. Come in:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
O
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
Se impostato stdin=PIPE
, communicate
consente anche di passare i dati al processo tramite stdin
:
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
Nota La risposta di Aaron Hall , che indica che su alcuni sistemi, potrebbe essere necessario insieme stdout
, stderr
e stdin
tutti a PIPE
(o DEVNULL
) per arrivare communicate
a lavoro a tutti.
In alcuni rari casi, potrebbe essere necessario acquisire output complessi e in tempo reale. La risposta di Vartec suggerisce una via da seguire, ma metodi diversi da quelli communicate
soggetti a deadlock se non utilizzati con attenzione.
Come per tutte le funzioni di cui sopra, quando la sicurezza non è un problema, è possibile eseguire comandi di shell più complessi passando shell=True
.
Appunti
1. Esecuzione dei comandi shell: l' shell=True
argomento
Normalmente, ogni chiamata a run
, check_output
o il Popen
costruttore esegue un singolo programma . Ciò significa che non ci sono pipe eleganti in stile bash. Se si desidera eseguire comandi shell complessi, è possibile passare shell=True
, che supportano tutte e tre le funzioni.
Tuttavia, ciò solleva problemi di sicurezza . Se stai facendo qualcosa di più di uno script leggero, potresti fare meglio a chiamare ciascun processo separatamente e passare l'output da ciascuno come input al successivo, tramite
run(cmd, [stdout=etc...], input=other_output)
O
Popen(cmd, [stdout=etc...]).communicate(other_output)
La tentazione di collegare direttamente i tubi è forte; resistergli. Altrimenti, probabilmente vedrai deadlock o dovrai fare cose bizzarre come questa .
2. Considerazioni su Unicode
check_output
restituisce una stringa in Python 2, ma un bytes
oggetto in Python 3. Vale la pena dedicare un momento a conoscere unicode se non l'hai già fatto.