python python-3.x

python - Obtenga el código de salida y stderr de la llamada de subproceso



python-3.x (4)

Leí las funciones provistas por el subproceso - llamada, marca de verificación, verificación de salida, y entiendo cómo funciona cada uno y difiere en funcionalidad uno del otro. Actualmente estoy usando check_output, así que puedo tener acceso a stdout, y usé "try block" para atrapar la excepción, de la siguiente manera:

# "cmnd" is a string that contains the command along with it''s arguments. try: cmnd_output = check_output(cmnd, stderr=STDOUT, shell=True, timeout=3, universal_newlines=True); except CalledProcessError: print("Status : FAIL") print("Output: /n{}/n".format(cmnd_output))

El problema al que me estoy enfrentando es cuando se lanza una excepción, "cmnd_output" no se inicializa y no tiene acceso a stderr, y aparece el siguiente mensaje de error:

print("Output: /n{}/n".format(cmnd_output)) UnboundLocalError: local variable ''cmnd_output'' referenced before assignment

Creo que eso se debe a que la excepción hace que el "check_output" se resguarde inmediatamente sin ningún procesamiento posterior, también conocido como asignación a "cmnd_output", en el bloque try. Por favor, corríjame si estoy equivocado.

¿Hay alguna manera de que pueda obtener acceso a stderr (está bien si se envía a stoutr) y tener acceso al código de salida? Puedo verificar manualmente si se aprueban o no según el código de salida sin que se produzca la excepción.

Gracias, Ahmed.


¿por qué no inicializar el varible cmnd_output antes de la instrucción try? De esa forma funcionará de la manera que usted espera. La siguiente línea funcionaría, solo agréguela encima de la declaración try:

cmnd_output = ''''


Ambas soluciones propuestas mezclan stdout / stderr o usan Popen que no es tan fácil de usar como check_output . Sin embargo, puede lograr lo mismo y mantener stdout / stderr por separado, mientras usa check_output si simplemente captura stderr usando una tubería:

import sys import subprocess try: subprocess.check_output(cmnd, stderr=subprocess.PIPE) except subprocess.CalledProcessError as e: print(''exit code: {}''.format(e.returncode)) print(''stdout: {}''.format(e.output.decode(sys.getfilesystemencoding()))) print(''stderr: {}''.format(e.stderr.decode(sys.getfilesystemencoding())))

En este ejemplo, dado que capturamos stderr, está disponible en el atributo stderr la excepción (sin capturar con el conducto, simplemente sería None ).


La solución aceptada cubre el caso en el que está bien mezclar stdout y stderr , pero en los casos en que el proceso hijo (por cualquier razón) decide usar stderr ADEMÁS de stdout para un resultado no fallado (es decir, para generar un resultado no crítico advertencia), entonces la solución dada puede no ser deseable.

Por ejemplo, si va a hacer un procesamiento adicional en la salida, como convertir a JSON, y mezcla en el stderr , entonces el proceso general fallará ya que el resultado no será JSON puro debido a la salida de stderr agregada.

He encontrado lo siguiente para trabajar en ese caso:

cmd_args = ... what you want to execute ... pipes = subprocess.Popen(cmnd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) std_out, std_err = pipes.communicate() if pipes.returncode != 0: # an error happened! err_msg = "%s. Code: %s" % (std_err.strip(), pipes.returncode) raise Exception(err_msg) elif len(std_err): # return code is 0 (no error), but we may want to # do something with the info on std_err # i.e. logger.warning(std_err) # do whatever you want with std_out # i.e. json.loads(std_out)


Prueba esta versión:

import subprocess try: output = subprocess.check_output( cmnd, stderr=subprocess.STDOUT, shell=True, timeout=3, universal_newlines=True) except subprocess.CalledProcessError as exc: print("Status : FAIL", exc.returncode, exc.output) else: print("Output: /n{}/n".format(output))

De esta forma, imprimirá la salida solo si la llamada fue exitosa. En el caso de un CalledProcessError imprime el código de retorno y la salida.