Envolver subproceso ‘stdout / stderr

Me gustaría tanto capturar como mostrar la salida de un proceso que invoco a través del subproceso de Python.

Pensé que solo podía pasar mi objeto tipo archivo con el nombre de parámetro stdout y stderr

Puedo ver que accede al atributo fileno , por lo que está haciendo algo con el objeto. Sin embargo, el método write() nunca se invoca. ¿Mi enfoque está completamente apagado o simplemente me estoy perdiendo algo?

 class Process(object): class StreamWrapper(object): def __init__(self, stream): self._stream = stream self._buffer = [] def _print(self, msg): print repr(self), msg def __getattr__(self, name): if not name in ['fileno']: self._print("# Redirecting: %s" % name) return getattr(self._stream, name) def write(self, data): print "###########" self._buffer.append(data) self._stream.write(data) self._stream.flush() def getBuffer(self): return self._buffer[:] def __init__(self, *args, **kwargs): print ">> Running `%s`" % " ".join(args[0]) self._stdout = self.StreamWrapper(sys.stdout) self._stderr = self.StreamWrapper(sys.stderr) kwargs.setdefault('stdout', self._stdout) kwargs.setdefault('stderr', self._stderr) self._process = subprocess.Popen(*args, **kwargs) self._process.communicate() 

Actualizar:

Algo en lo que me gustaría trabajar también, son los caracteres de control ANSI para mover el cursor y anular las cosas de salida anteriores. No sé si ese es el término correcto, pero aquí hay un ejemplo de lo que quise decir: estoy tratando de automatizar algunas cosas de GIT y ahí están los avances que se actualizan sin necesidad de escribir en una nueva línea cada vez.

Actualización 2

Para mí es importante que la salida del subproceso se muestre inmediatamente. He intentado usar subprocess.PIPE para capturar la salida y mostrarla manualmente, pero solo pude hacer que muestre la salida, una vez que el proceso se hubo completado. Sin embargo, me gustaría ver la salida en tiempo real.

Stdin, stdout y stderr de un proceso deben ser descriptores de archivos reales. (En realidad, no es una restricción impuesta por Python, sino cómo funcionan las canalizaciones en el nivel del sistema operativo). Por lo tanto, necesitará una solución diferente.

Si desea realizar un seguimiento de ambos stdout y stderr en tiempo real, necesitará I / O asíncrono o subprocesos.

  • E / S asíncrona: con la E / S síncrona estándar (= locking), una lectura de uno de los flujos podría bloquearse, lo que no permite el acceso al otro en tiempo real. Si está en Unix, puede usar E / S sin locking como se describe en esta respuesta . Sin embargo, en Windows no tendrás suerte con este enfoque. Más información sobre la E / S asíncrona en Python y algunas alternativas se muestran en este video .

  • Subprocesos: otra forma común de resolver este problema es crear un subproceso para cada descriptor de archivo que desea leer en tiempo real. Los subprocesos solo manejan el descriptor de archivo al que están asignados, por lo que bloquear la E / S no perjudicará.

Echa un vistazo aquí .

 p = subprocess.Popen(cmd, shell=True, bufsize=64, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) 

Un archivo como no está lo suficientemente cerca. Debe ser un archivo real con un descriptor de archivo real. Utilice el soporte de subprocess para las tuberías y léalas según corresponda.

¿Hay alguna razón para que tengas una clase dentro de una clase? Y stdout y stderr pueden tomar cualquier archivo como línea, por ejemplo, intente. Así que simplemente pasar un tipo de archivo abierto o stringIO debería ser suficiente para modificar la secuencia

 import sys sys.stdout = open('test.txt','w') print "Testing!" sys.stdout.write('\nhehehe') sys.stdout = sys.__stdout__ sys.exit(0)