Limpieza de Popen en Python

Quería usar un equivalente de python para canalizar algunos comandos de shell en perl. Algo como la versión python de open (PIPE, “command |”).

Voy al módulo de subproceso e bash esto:

p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE) 

Esto funciona para leer la salida de la misma manera que lo haría en perl, pero no se limpia solo. Cuando salgo del intérprete, me sale

 grep: writing output: Broken pipe 

arrojado por todo el stderr unos pocos millones de veces. Supongo que ingenuamente había esperado que todo esto fuera atendido por mí, pero eso no es cierto. Llamar a terminar o matar en p no parece ayudar. Mire la tabla de procesos, veo que esto mata el proceso / bin / sh, pero deja el gzip del niño en su lugar para quejarse de la tubería rota.

¿Cuál es la forma correcta de hacer esto?

El problema es que la pipe está llena. El subproceso se detiene y espera a que se vacíe la tubería, pero luego su proceso (el intérprete de Python) se cierra, rompiendo su extremo de la tubería (de ahí el mensaje de error).

p.wait() no te ayudará:

Advertencia Esto se interrumpirá si el proceso hijo genera suficiente salida en una salida estándar o en una tubería estándar, de modo que bloquea la espera de que el búfer de la tubería del sistema operativo acepte más datos. Utilice communicate() para evitar eso.

http://docs.python.org/library/subprocess.html#subprocess.Popen.wait

p.communicate() no te ayudará:

Nota La lectura de los datos se almacena en la memoria intermedia, por lo que no utilice este método si el tamaño de los datos es grande o ilimitado.

http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate

p.stdout.read(num_bytes) no te ayudará:

Advertencia Use communicate() lugar de .stdin.write , .stdout.read o .stderr.read para evitar interlockings debido a que cualquiera de los otros buffers de tuberías del sistema operativo .stderr.read y bloqueen el proceso secundario.

http://docs.python.org/library/subprocess.html#subprocess.Popen.stdout

La moraleja de la historia es, para grandes resultados, subprocess.PIPE lo condenará a ciertas fallas si su progtwig está intentando leer los datos (me parece que debería poder poner p.stdout.read(bytes) en a while p.returncode is None: loop, pero la advertencia anterior sugiere que esto podría interrumpirse).

Los documentos sugieren reemplazar un tubo de shell con esto:

 p1 = Popen(["zgrep", "thingiwant", "largefile"], stdout=PIPE) p2 = Popen(["processreceivingdata"], stdin=p1.stdout, stdout=PIPE) output = p2.communicate()[0] 

Tenga en cuenta que p2 está tomando su entrada estándar directamente desde p1 . Esto debería evitar puntos muertos, pero dadas las advertencias contradictorias anteriores, quién sabe .

De todos modos, si esa última parte no funciona para usted (aunque debería ), puede intentar crear un archivo temporal, escribir todos los datos de la primera llamada y luego utilizar el archivo temporal como entrada para el siguiente proceso.

Después de abrir el conducto, puede trabajar con el comando de salida: p.stdout :

 for line in p.stdout: # do stuff p.stdout.close() 

¿Cómo ejecutaste este proceso?

La forma correcta es usar

 p.communicate() 

Ver documentos para más detalles.

Necesitas wait a que finalice el proceso:

 import subprocess p = subprocess.Popen("cat /mach_kernel", shell=True) p.wait() 

Alternativamente, puede capturar la salida estándar del progtwig (como lo ha hecho), y quizás su error estándar, y luego llamar a communicate :

 import subprocess p = subprocess.Popen("cat /mach_kernel", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate()