Cómo usar el comando `subprocess` con tuberías

Respuestas:

439

Para usar una tubería con el subprocessmódulo, debe pasar shell=True.

Sin embargo, esto no es realmente aconsejable por varias razones, entre ellas la seguridad. En su lugar, cree los procesos psy por grepseparado, y canalice la salida de uno a otro, así:

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

En su caso particular, sin embargo, la solución simple es llamar subprocess.check_output(('ps', '-A'))y luego str.finden la salida.

Taymon
fuente
81
+1 para separar la salida / entrada para evitar el usoshell=True
Nicolas
55
No olvide que el error subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1solo significa que grep no encontró nada, por lo que es un comportamiento normal.
Serge
2
¿Por qué necesitamos el ps.wait()para cuando ya tenemos la salida? ps.wait.__doc__espera que el niño termine pero el contenido del niño ya parece estar colocado en la outputvariable
Papouche Guinslyzinho
3
@MakisH Estás viendo string.find, que ha quedado en desuso a favor str.find(es decir, el método finden los strobjetos).
Taymon
44
nota: si grepmuere prematuramente; pspuede colgarse indefinidamente si produce una salida suficiente para llenar su búfer de canalización del sistema operativo (porque no ha llamado ps.stdout.close()al padre). Cambie el orden de inicio, para evitarlo
jfs
54

O siempre puede usar el método de comunicación en los objetos de subproceso.

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

El método de comunicación devuelve una tupla de la salida estándar y el error estándar.

jkalivas
fuente
3
Creo que usar communicatees mejor que wait. Existe una advertencia de este tipo: "Esto se bloqueará cuando se use stdout = PIPE y / o stderr = PIPE y el proceso secundario genera suficiente salida para una tubería de manera que bloquea la espera de que el búfer de tubería del sistema operativo acepte más datos. Utilice la comunicación () para evitar eso ".
Paolo
2
Para aclarar el comentario anterior de Paolo, la advertencia es para esperar, no para comunicarse, es decir, es la razón por la que dice que comunicarse es mejor.
EnemyBagJones
23

Consulte la documentación sobre la configuración de una tubería mediante el subproceso: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

No he probado el siguiente ejemplo de código, pero debería ser aproximadamente lo que quieres:

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]
AlcubierreDrive
fuente
2
Al comprobar que esto falló, vea la respuesta a continuación de Taymon para algo que funciona sin perder el tiempo
Alvin
2
subprocess.check_output no parece existir en Python 2.6.9
RightmireM
6

La solución de JKALAVIS es buena, sin embargo, agregaría una mejora para usar shlex en lugar de SHELL = TRUE. a continuación estoy agotando tiempos de consulta

#!/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)
Daniel Smith
fuente
1
¿Por qué shellx sobre shell?
AFP_555
2
¿Dónde se usa Shlex aquí?
3lokh
4

Además, intente usar el 'pgrep'comando en lugar de'ps -A | grep 'process_name'

Shooe
fuente
2
si quieres obtener la identificación del proceso, obviamente
Shooe
3

Puede probar la funcionalidad de tubería en sh.py :

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

Después de Python 3.5 también puedes usar:

    import subprocess

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

La ejecución del comando está bloqueando y la salida estará en process.stdout .

zingi
fuente