Redirigir subproceso stderr a stdout

Quiero redireccionar la salida stderr de un subproceso a stdout. La constante STDOUT debería hacer eso, ¿no es así?

Sin embargo,

 $ python >/dev/null -c 'import subprocess;\ subprocess.call(["ls", "/404"],stderr=subprocess.STDOUT)' 

hace salir algo. ¿Por qué es así, y cómo obtengo el mensaje de error en la salida estándar?

Una lectura atenta del código fuente da la respuesta. En particular, la documentación es engañosa cuando dice:

subprocess.STDOUT
Valor especial que (…) indica que el error estándar debe ir al mismo identificador que la salida estándar.

Dado que stdout se establece en “predeterminado” ( -1 , técnicamente) cuando se evalúa stderr=subprocess.STDOUT , stderr también se establece en “predeterminado”. Desafortunadamente, esto significa que la salida de stderr todavía va a stderr.

Para resolver el problema, pase el archivo stdout en lugar de subprocess.STDOUT :

 $ python >/dev/null -c 'import subprocess,sys;subprocess.call(["ls", "/404"], stderr=sys.stdout.buffer)' 

O, por compatibilidad con las versiones 2.x de Python heredadas:

 $ python >/dev/null -c 'import subprocess,sys;subprocess.call(["ls", "/404"], stderr=sys.stdout.fileno())' 

En realidad, el uso de subprocess.STDOUT hace exactamente lo que se indica en la documentación: redirige stderr a stdout para que, por ejemplo,

 proc = subprocess.Popen(self.task["command"], shell=False, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = "" while (True): # Read line from stdout, break if EOF reached, append line to output line = proc.stdout.readline() line = line.decode() if (line == ""): break output += line 

da como resultado una output variable output contiene la output del proceso tanto de stdout como de stderr.

stderr=subprocess.STDOUT redirige todas las salidas de stderr directamente a la salida estándar del proceso de llamada, que es una diferencia importante.