Combinar y sincronizar stdout y stderr?

decir que estoy ejecutando un exe desde un script de python usando:

subprocess.call(cmdArgs,stdout=outf, stderr=errf)

cuando outf y errf son descriptores de archivos de texto.

¿Hay alguna manera de que pueda generar un archivo de texto combinado y sincronizado de stdout y stderr? debe estar formateado con el tiempo y la fuente (nuestro / err).

Gracias

Es un poco complicado, ya que necesita sondear los descriptores de archivo stdout y stderr del subproceso mientras se está ejecutando, para obtener marcas de tiempo precisas. También debe dividir la salida en una lista de líneas para que los resultados finales se puedan combinar y clasificar fácilmente. Podría fusionar fácilmente las dos secuencias a medida que se leen, pero eso no era parte de la pregunta.

Lo escribí rápidamente, pero podría hacerse más limpio y más compacto:

 import datetime import os import select import subprocess class Stream(object): def __init__(self, name, impl): self._name = name self._impl = impl self._buf = '' self._rows = [] def fileno(self): "Pass-through for file descriptor." return self._impl.fileno() def read(self, drain=0): "Read from the file descriptor. If 'drain' set, read until EOF." while self._read() is not None: if not drain: break def _read(self): "Read from the file descriptor" fd = self.fileno() buf = os.read(fd, 4096) if not buf: return None if '\n' not in buf: self._buf += buf return [] # prepend any data previously read, then split into lines and format buf = self._buf + buf tmp, rest = buf.rsplit('\n', 1) self._buf = rest now = datetime.datetime.now().isoformat() rows = tmp.split('\n') self._rows += [(now, '%s %s: %s' % (self._name, now, r)) for r in rows] def run(cmd, timeout=0.1): """ Run a command, read stdout and stderr, prefix with timestamp, and return a dict containing stdout, stderr and merged. """ PIPE = subprocess.PIPE proc = subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE) streams = [ Stream('stdout', proc.stdout), Stream('stderr', proc.stderr) ] def _process(drain=0): res = select.select(streams, [], [], timeout) for stream in res[0]: stream.read(drain) while proc.returncode is None: proc.poll() _process() _process(drain=1) # collect results, merge and return result = {} temp = [] for stream in streams: rows = stream._rows temp += rows result[stream._name] = [r[1] for r in rows] temp.sort() result['merged'] = [r[1] for r in temp] return result res = run(['ls', '-l', '.', 'xyzabc']) for key in ('stdout', 'stderr', 'merged'): print print '\n'.join(res[key]) print '-'*40 

Ejemplo de salida:

 stdout 2011-03-03T19:30:44.838145: .: stdout 2011-03-03T19:30:44.838145: total 0 stdout 2011-03-03T19:30:44.838338: -rw-r--r-- 1 pat pat 0 2011-03-03 19:30 bar stdout 2011-03-03T19:30:44.838518: -rw-r--r-- 1 pat pat 0 2011-03-03 19:30 foo ---------------------------------------- stderr 2011-03-03T19:30:44.837189: ls: cannot access xyzabc: No such file or directory ---------------------------------------- stderr 2011-03-03T19:30:44.837189: ls: cannot access xyzabc: No such file or directory stdout 2011-03-03T19:30:44.838145: .: stdout 2011-03-03T19:30:44.838145: total 0 stdout 2011-03-03T19:30:44.838338: -rw-r--r-- 1 pat pat 0 2011-03-03 19:30 bar stdout 2011-03-03T19:30:44.838518: -rw-r--r-- 1 pat pat 0 2011-03-03 19:30 foo ---------------------------------------- 

Puede combinarlos pasando subprocess.STDOUT como el argumento stderr para subprocess.Popen , pero no sé si se formatearán con el tiempo y la fuente.