uniendo varios subprocesos

Tengo 5 procesos p1,p2,...,p5 donde quiero escribir algunos datos en la entrada estándar de p1, canalizar la salida de p1 en la entrada de p2 y finalmente leer el resultado final de la salida de p5.

Lo que he intentado hasta ahora:

 p1 = Popen(['p1'], stdin=PIPE, stdout=PIPE) p2 = Popen(['p2'], stdin=p1.stdout, stdout=PIPE) ... p5 = Popen(['p5'], stdin=p4.stdout, stdout=PIPE) # write data to stdin p1.stdin.write(indata) p1.stdin.close() # not sure in what order to close the pipes here, if at all # read output out = p5.stdout.read() print out 

El último código cortado simplemente se cuelga, porque debo estar haciendo las operaciones de lectura / escritura incorrectamente.

Pude hacer que funcionen procesos únicos utilizando communicate() y dos procesos sin aportar ninguna entrada a la primera (ejemplo de documentos de Python):

 output=`dmesg | grep hda` ==> p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits. output = p2.communicate()[0] 

Pero no puedo averiguar cómo proporcionar información al primer proceso sin colgar al intérprete.

También podría usar un script de bash para eso (que ya he escrito y funciona), pero me gustaría saber cómo lograr lo mismo con Python.

Entonces, me gustaría preguntar, ¿cómo se hace todo eso correctamente, específicamente en qué orden hacer las operaciones de lectura / escritura / cierre en las tuberías?

Estoy trabajando en Linux de 64 bits, si eso importa.

EDITAR: Olvidé mencionar que todos los procesos p1, .. p5 consumen toda la entrada que se les da, lo procesan, escriben en la salida estándar y luego finalizan. Por lo tanto, los procesos que siguen en la tubería no deben terminar antes de que los anteriores hayan terminado de procesarse.

EDIT2: Sé que también podría usar

 command = 'bash -c "p1 | p2 | p3 | p4 | p5"' proc = Popen([command], shell=True) out, err = proc.communicate(input=indata) print out 

pero mi principal interés es obtener información sobre cómo encadenar las tuberías únicamente en código Python.

Tal vez esto pueda ayudar:

 import sys import tempfile from subprocess import Popen, PIPE cmd = [sys.executable, '-c', 'print raw_input()'] # Using a temp file to give input data to the subprocess instead of stdin.write to avoid deadlocks. with tempfile.TemporaryFile() as f: f.write('foobar') f.seek(0) # Return at the start of the file so that the subprocess p1 can read what we wrote. p1 = Popen(cmd, stdin=f, stdout=PIPE) p2 = Popen(cmd, stdin=p1.stdout, stdout=PIPE) p3 = Popen(cmd, stdin=p2.stdout, stdout=PIPE) # No order needed. p1.stdout.close() p2.stdout.close() # Using communicate() instead of stdout.read to avoid deadlocks. print p3.communicate()[0] 

Salida:

 $ python test.py foobar 

Espero que esto pueda ser hepático.