Python: ¿captura la salida estándar de Popen Y se muestra en la consola?

Quiero capturar stdout desde un proceso de ejecución larga-ish iniciado a través de subprocess.Popen(...) así que estoy usando stdout=PIPE como argumento.

Sin embargo, debido a que es un proceso de larga ejecución, también quiero enviar el resultado a la consola (como si no lo hubiera canalizado) para que el usuario del script tenga una idea de que aún funciona.

¿Es esto posible?

Aclamaciones.

¿Puedes simplemente print mientras lo lees desde la tubería?

El almacenamiento en búfer que está realizando su subproceso de ejecución probablemente hará que la salida de su consola sea desigual y muy mala. Le sugiero que considere utilizar pexpect (o, en Windows, wexpect ) para eliminar dicho almacenamiento en búfer y obtener una salida regular y sin problemas del subproceso. Por ejemplo (en casi cualquier sistema unix-y, después de instalar pexpect):

 >>> import pexpect >>> child = pexpect.spawn('/bin/bash -c "echo ba; sleep 1; echo bu"', logfile=sys.stdout); x=child.expect(pexpect.EOF); child.close() ba bu >>> child.before 'ba\r\nbu\r\n' 

El ba y el bu vendrán con la sincronización apropiada (alrededor de un segundo entre ellos). Tenga en cuenta que la salida no está sujeta al procesamiento normal de la terminal, por lo que los retornos de carro se quedan allí, usted deberá postprocesar la cadena usted mismo (¡solo un simple .replace ! -) si necesita \n como final de Marcadores de línea (la falta de procesamiento es importante en caso de que el subproceso esté escribiendo datos binarios en su salida estándar). ¡Esto garantiza que todos los datos queden intactos! -).

El comentario de S. Lott apunta a Obtener salida en tiempo real utilizando subproceso y la intercepción en tiempo real de la salida estándar de otro proceso en Python

Tengo curiosidad de que la respuesta de Alex aquí sea diferente de su respuesta 1085071. Mis pequeños experimentos sencillos con las respuestas en las otras dos preguntas referenciadas han dado buenos resultados …

Fui y miré a Wexpect según la respuesta de Alex anterior, pero tengo que decir que al leer los comentarios en el código no me dejó una sensación muy buena de usarlo.

Supongo que la meta-pregunta aquí es ¿cuándo será pexpect / wexpect una de las baterías incluidas?

Inspirado por la sugerencia de pty.openpty () en algún lugar arriba, probado en python2.6, linux. Publicación, ya que tomó un tiempo hacer que esto funcione correctamente, sin almacenamiento en búfer …

 def call_and_peek_output(cmd, shell=False): import pty, subprocess master, slave = pty.openpty() p = subprocess.Popen(cmd, shell=shell, stdin=None, stdout=slave, close_fds=True) os.close(slave) line = "" while True: try: ch = os.read(master, 1) except OSError: # We get this exception when the spawn process closes all references to the # pty descriptor which we passed him to use for stdout # (typically when it and its childs exit) break line += ch sys.stdout.write(ch) if ch == '\n': yield line line = "" if line: yield line ret = p.wait() if ret: raise subprocess.CalledProcessError(ret, cmd) for l in call_and_peek_output("ls /", shell=True): pass 

Alternativamente, puede canalizar su proceso hacia el tee y capturar solo uno de los flujos. Algo en la línea de sh -c 'process interesting stuff' | tee /dev/stderr sh -c 'process interesting stuff' | tee /dev/stderr .

Por supuesto, esto solo funciona en sistemas similares a Unix.