2012-07-15 11 views
24

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

Sin embargo,

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

hace algo de salida. ¿Por qué es ese el caso y cómo obtengo el mensaje de error en stdout?

+0

Por cierto, está arreglado en python 3.5. – max

Respuesta

29

Una lectura detallada del source code da la respuesta. En particular, el documentation es engañosa cuando dice:

subprocess.STDOUT
valor especial que (...) indica que el error estándar debe entrar en el mismo mango como salida estándar.

Desde stdout se establece en "default" (-1, técnicamente) cuando se evalúa stderr=subprocess.STDOUT, stderr está ajustado en "default" también. Desafortunadamente, esto significa que la salida de stderr todavía va a stderr.

Para resolver el problema, pase en el archivo de salida estándar en lugar de subprocess.STDOUT:

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

O, para la compatibilidad con versiones 2.x legado de Python:

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

Uno puede dejar stderr tal como está: 'stderr = sys.stderr.fileno()'. Buen ejemplo; Simplemente voy a utilizar esta técnica en todos mis scripts. Tenemos Python 2.x heredado; así sabré exactamente dónde lo dije que vaya sin confusión. –

6

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 

resultados en salida que contiene la salida del proceso de ambos stdout y stderr.

stderr=subprocess.STDOUT redirige toda la salida de stderr directamente a la salida estándar del proceso de llamada, que es una gran diferencia.

+0

-1 Este caso es irrelevante para la pregunta que trata de que 'stdout' sea' None'. Y 'subprocess.STDOUT' no redirige a la" consola de llamadas "(creo que se refiere al manejador de archivo 1 que se le dio al proceso actual), como lo muestra su propio ejemplo: si llama a Popen con' ['ls', '/404 '] ', el [mensaje de error no se muestra] (http://ideone.com/2JhcRT). – phihag

+0

Tienes razón. Sin embargo, no creo que esto sea irrelevante en absoluto, ya que esto tiene la intención de aclarar su publicación con respecto a la documentación que es engañosa, que no es el caso. Hubiera dejado un comentario debajo de tu publicación, pero hace un año no me lo permitieron. – Maxxim

+0

'python -c 'import subprocess, sys; subprocess.call ([" ls ","/404 "], stderr = subprocess.STDOUT)' 2>/dev/null' muestra que el stderr de' ls' va a stderr (descriptor de archivo 2) porque no verá ningún resultado (suponiendo que no tiene '/ 404' en su sistema). Esa documentación de Python realmente olfateó ese tema, y ​​es especialmente molesto para nosotros, los intérpretes de comandos de shell, que estamos acostumbrados a manipular stdout/stderr en innumerables formas, y tenemos que venir aquí a SO solo para descubrir cómo hacer algo que debería ser simple y simple. no confuso –

Cuestiones relacionadas