Python – ¿Cómo ejecutar comandos de shell con pipe?

Tengo un caso para querer ejecutar el siguiente comando de shell en Python y obtener la salida,

echo This_is_a_testing | grep -c test 

Podría usar este código de Python para ejecutar el comando de shell anterior en Python,

 >>> import subprocess >>> subprocess.check_output("echo This_is_a_testing | grep -c test", shell=True) '1\n' 

Sin embargo, como no quiero usar la opción “shell = True”, probé el siguiente código de Python,

 >>> import subprocess >>> p1 = subprocess.Popen(["echo", "This_is_a_testing"], stdout=subprocess.PIPE) >>> p2 = subprocess.Popen(["grep", "-c", "test"], stdin=p1.stdout) >>> p1.stdout.close() >>> p2.communicate() (None, None) 

Me pregunto por qué el resultado es “Ninguno”, ya que me he referido a las descripciones en la página web: http://docs.python.org/library/subprocess.html#subprocess.PIPE

¿Me había perdido algunos puntos en mi código? ¿Alguna sugerencia / idea? Gracias por adelantado.

Del manual:

para obtener algo que no sea Ninguno en la tupla de resultados, debe proporcionar stdout = PIPE y / o stderr = PIPE

 p2 = subprocess.Popen(["grep", "-c", "test"], stdin=p1.stdout, stdout=subprocess.PIPE) 

Por favor mire aquí:

 >>> import subprocess >>> p1 = subprocess.Popen(["echo", "This_is_a_testing"], stdout=subprocess.PIPE) >>> p2 = subprocess.Popen(["grep", "-c", "test"], stdin=p1.stdout) >>> 1 p1.stdout.close() >>> p2.communicate() (None, None) >>> 

aquí obtiene 1 como salida después de escribir p2 = subprocess.Popen(["grep", "-c", "test"], stdin=p1.stdout) , No ignore esta salida en el contexto de su pregunta.

Si esto es lo que quieres, entonces pasa stdout=subprocess.PIPE como argumento al segundo Popen :

 >>> p1 = subprocess.Popen(["echo", "This_is_a_testing"], stdout=subprocess.PIPE) >>> p2 = subprocess.Popen(["grep", "test"], stdin=p1.stdout, stdout=subprocess.PIPE) >>> p2.communicate() ('This_is_a_testing\n', None) >>> 
 >>> import subprocess >>> mycmd=subprocess.getoutput('df -h | grep home | gawk \'{ print $1 }\' | cut -d\'/\' -f3') >>> mycmd 'sda6' >>> 

Si bien la respuesta aceptada es correcta / funciona, otra opción sería usar el método Popen.communicate() para pasar algo a un proceso estándar:

 >>> import subprocess >>> p2 = subprocess.Popen(["grep", "-c", "test"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) >>> p2.communicate("This_is_a_testing") ('1\n', None) >>> print p2.returncode 0 >>>> 

Esto resuelve la necesidad de ejecutar otro comando solo para redirigir su salida, si la salida ya es conocida en el propio script de Python.

Sin embargo, communicate tiene el efecto secundario, que espera a que finalice el proceso. Si la ejecución asíncrona es necesaria / deseada, usar dos procesos podría ser la mejor opción.