Come usare il comando `subprocess` con i pipe


Risposte:


439

Per usare una pipe con il subprocessmodulo, devi passare shell=True.

Tuttavia, questo non è davvero consigliabile per vari motivi, non ultimo quello della sicurezza. Invece, crea i processi pse grepseparatamente e convoglia l'output dall'uno all'altro, in questo modo:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

Nel tuo caso particolare, tuttavia, la soluzione semplice è chiamare subprocess.check_output(('ps', '-A'))e quindi str.findsull'output.


81
+1 per separare l'uscita / ingresso di evitare l'usoshell=True
Nicolas

5
Non dimenticare, l'errore subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1significa semplicemente che non è stato trovato nulla da grep, quindi è un comportamento normale.
Serge

2
Perché abbiamo bisogno del ps.wait()per quando abbiamo già l'output. ps.wait.__doc__attende che il bambino termini, ma il contenuto del bambino sembra già inserito nella outputvariabile
Papouche Guinslyzinho,

3
@MakisH Stai guardando string.find, che è stato deprecato a favore di str.find(cioè, il metodo findsugli stroggetti).
Taymon,

4
nota: se grepmuore prematuramente; pspotrebbe bloccarsi indefinitamente se produce abbastanza output per riempire il suo buffer di pipe del sistema operativo (perché non hai chiamato ps.stdout.close()nel padre). Scambia l'ordine di partenza, per evitarlo
jfs

54

In alternativa, è sempre possibile utilizzare il metodo di comunicazione sugli oggetti sottoprocesso.

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

Il metodo di comunicazione restituisce una tupla dell'output standard e dell'errore standard.


3
Penso che usare communicatesia meglio di wait. Esiste tale avviso: "Questo si bloccherà quando si utilizza stdout = PIPE e / o stderr = PIPE e il processo figlio genera un output sufficiente per una pipe in modo tale da bloccare l'attesa del buffer della pipe del sistema operativo per accettare più dati. Utilizzare communic () per evitatelo ".
Paolo

2
Per chiarire il commento di Paolo sopra, l'avvertimento è di aspettare, non di comunicare - cioè è la ragione per cui dice che comunicare è meglio.
EnemyBagJones

23

Consulta la documentazione sulla configurazione di una pipeline tramite sottoprocesso: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Non ho testato il seguente esempio di codice ma dovrebbe essere più o meno quello che vuoi:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]

2
Dopo aver verificato che ciò non è riuscito, vedi la risposta sotto di Taymon per qualcosa che funziona senza perdere tempo
Alvin,

2
subprocess.check_output non sembra esistere in Python 2.6.9
RightmireM

6

La soluzione JKALAVIS è buona, tuttavia aggiungerei un miglioramento per usare shlex invece di SHELL = TRUE. di seguito im grepping out Query times

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

1
Perché shellx over shell?
AFP_555,

2
dove viene usato shlex?
3lokh,

4

Inoltre, prova a utilizzare il 'pgrep'comando anziché'ps -A | grep 'process_name'


2
se vuoi ottenere l'ID del processo, ovviamente
Shooe

3

Puoi provare la funzionalità pipe in sh.py :

import sh
print sh.grep(sh.ps("-ax"), "process_name")

-1

Dopo Python 3.5 puoi anche usare:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

L'esecuzione del comando sta bloccando e l'output sarà in process.stdout .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.