Guardando stdout de subprocess.Popen en el archivo, además de escribir más cosas en el archivo

Estoy escribiendo una secuencia de comandos de Python que utiliza subprocess.Popen para ejecutar dos progtwigs (a partir de código C comstackdo), cada uno de los cuales produce una salida estándar. El script obtiene esa salida y la guarda en un archivo. Debido a que la salida es a veces lo suficientemente grande como para abrumar a subprocess.PIPE, lo que provoca que el script se cuelgue, envío la salida estándar directamente al archivo de registro. Quiero que mi script escriba algo al principio y al final del archivo, y entre las dos llamadas de subproceso.Popen. Sin embargo, cuando miro mi archivo de registro, todo lo que escribí en el archivo de registro desde la secuencia de comandos está todo junto en la parte superior del archivo, seguido de toda la salida estándar ejecutable. ¿Cómo puedo intercalar mi texto agregado al archivo?

def run(cmd, logfile): p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile) return p def runTest(path, flags, name): log = open(name, "w") print >> log, "Calling executable A" a_ret = run(path + "executable_a_name" + flags, log) print >> log, "Calling executable B" b_ret = run(path + "executable_b_name" + flags, log) print >> log, "More stuff" log.close() 

El archivo de registro tiene: Llamando al ejecutable A Llamando al ejecutable B Más cosas [… stdout de ambos ejecutables …]

¿Hay alguna manera de poder vaciar la salida estándar de A al registro después de llamar a Popen, por ejemplo? Una cosa más que podría ser relevante: el ejecutable A comienza, luego se inclina sobre B, y después de que B imprime y termina, A luego imprime más y finaliza.

Estoy usando Python 2.4 en RHE Linux.

Puede llamar a .wait () en cada objeto Popen para asegurarse de que está terminado y luego llamar a log.flush (). Tal vez algo como esto:

 def run(cmd, logfile): p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile) ret_code = p.wait() logfile.flush() return ret_code 

Si necesita interactuar con el objeto Popen en su función externa, puede mover la llamada .wait () a ese lugar.

Debe esperar hasta que finalice el proceso antes de continuar. También he convertido el código para usar un administrador de contexto, que es más limpio.

 def run(cmd, logfile): p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile) p.wait() return p def runTest(path, flags, name): with open(name, "w") as log: print >> log, "Calling executable A" a_ret = run(path + "executable_a_name" + flags, log) print >> log, "Calling executable B" b_ret = run(path + "executable_b_name" + flags, log) print >> log, "More stuff" 

Yo digo que sea muy simple. Lógica básica del pseudo código:

 write your start messages to logA execute A with output to logA write your in-between messages to logB execute B with output to logB write your final messages to logB when A & B finish, write content of logB to the end of logA delete logB 

Según tengo entendido, el progtwig A espera que B haga su trabajo y A sale solo después de que B sale.

Si B puede comenzar sin que A ejecute, puede iniciar los procesos en orden inverso:

 from os.path import join as pjoin from subprocess import Popen def run_async(cmd, logfile): print >>log, "calling", cmd p = Popen(cmd, stdout=logfile) print >>log, "started", cmd return p def runTest(path, flags, name): log = open(name, "w", 1) # line-buffered print >>log, 'calling both processes' pb = run_async([pjoin(path, "executable_b_name")] + flags.split(), log) pa = run_async([pjoin(path, "executable_a_name")] + flags.split(), log) print >>log, 'started both processes' pb.wait() print >>log, 'process B ended' pa.wait() print >>log, 'process A ended' log.close() 

Nota: llamar a log.flush() en los procesos principales no tiene ningún efecto en los buffers de archivos en los procesos secundarios.

Si los procesos secundarios utilizan el almacenamiento en búfer para stdout, entonces podría intentar forzarlos a vaciarse antes usando pexpect, pty o stdbuf (se supone que los procesos usan el almacenamiento en línea si se ejecutan interactivamente o usan la biblioteca C stdio para E / S) .