“Subprocess.Popen” – comprobando el éxito y los errores

Quiero comprobar si un subproceso ha finalizado con éxito o ha fallado. Actualmente, he encontrado una solución, pero no estoy seguro de si es correcta y confiable. ¿Se garantiza que cada proceso produce sus errores solo para stderr respetuosamente para stdout ?

Nota: No estoy interesado en solo redirigir / imprimir la salida. Eso ya lo sé hacer.

 pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) if "" == pipe.stdout.readline(): print("Success") self.isCommandExectutionSuccessful = True if not "" == pipe.stderr.readline(): print("Error") self.isCommandExectutionSuccessful = True 

alternativamente:

  if "" == pipe.stdout.readline(): print("Success") self.isCommandExectutionSuccessful = True else: print("Error") self.isCommandExectutionSuccessful = False 

y:

  if not "" == pipe.stderr.readline(): print("Success") self.isCommandExectutionSuccessful = True else: print("Error") self.isCommandExectutionSuccessful = False 

¿Necesitas hacer algo con la salida del proceso?

El método check_call podría ser útil aquí. Vea los documentos de Python aquí: https://docs.python.org/2/library/subprocess.html#subprocess.check_call

A continuación, puede utilizar esto de la siguiente manera:

 try: subprocess.check_call(command) except subprocess.CalledProcessError: # There was an error - command exited with non-zero code 

Sin embargo, esto se basa en que el command devuelva un código de salida de 0 para completar con éxito y un valor distinto de cero para un error.

Si también necesita capturar la salida, entonces el método check_output puede ser más apropiado. Todavía es posible redirigir el error estándar si también lo necesita.

 try: proc = subprocess.check_output(command, stderr=subprocess.STDOUT) # do something with output except subprocess.CalledProcessError: # There was an error - command exited with non-zero code 

Consulte la documentación aquí: https://docs.python.org/2/library/subprocess.html#subprocess.check_output

Puede verificar el código de retorno del proceso usando el método check_call (). En caso de que si el proceso devolvió un valor distinto de cero, se levantará CalledProcessError.

  output,error=pipe.communicate() 

Esto esperará a que finalice el comando y le dará salida o error según el estado del comando.

Solución completa con verificación del código de retorno, stdout y stderr:

 import subprocess as sp # ok pipe = sp.Popen( 'ls /bin', shell=True, stdout=sp.PIPE, stderr=sp.PIPE ) # res = tuple (stdout, stderr) res = pipe.communicate() print("retcode =", pipe.returncode) print("res =", res) print("stderr =", res[1]) for line in res[0].decode(encoding='utf-8').split('\n'): print(line) # with error pipe = sp.Popen( 'ls /bing', shell=True, stdout=sp.PIPE, stderr=sp.PIPE ) res = pipe.communicate() print("retcode =", pipe.returncode) print("res =", res) print("stderr =", res[1]) 

Huellas dactilares:

 retcode = 0 res = (b'bash\nbunzip2\nbusybox\nbzcat\n...zmore\nznew\n', b'') stderr = b'' bash bunzip2 busybox bzcat ... zmore znew retcode = 2 res = (b'', b"ls: cannot access '/bing': No such file or directory\n") stderr = b"ls: cannot access '/bing': No such file or directory\n" 

Así es como lo hice finalmente:

  # Call a system process try: # universal_newlines - makes manual decoding of subprocess.stdout unnecessary output = subprocess.check_output(command, stderr=subprocess.STDOUT, universal_newlines=True) # Print out command's standard output (elegant) for currentLine in output: self.textEdit_CommandLineOutput.insertPlainText(currentLine) self.isCommandExecutionSuccessful = True except subprocess.CalledProcessError as error: self.isCommandExecutionSuccessful = False errorMessage = ">>> Error while executing:\n"\ + command\ + "\n>>> Returned with error:\n"\ + str(error.output) self.textEdit_CommandLineOutput.append(errorMessage) QMessageBox.critical(None, "ERROR", errorMessage) print("Error: " + errorMessage) except FileNotFoundError as error: errorMessage = error.strerror QMessageBox.critical(None, "ERROR", errorMessage) print("Error: ", errorMessage) 

Espero que sea de utilidad para otra persona.