[파이썬] subprocess `subprocess.CalledProcessError`: 예외 처리

In Python, the subprocess module provides a way to run external commands and interact with their inputs and outputs. However, when running a subprocess, there is always a possibility of an error occurring. One such error is the subprocess.CalledProcessError. In this blog post, we will explore how to handle this exception and gracefully handle errors when running external commands using the subprocess module.

Understanding subprocess.CalledProcessError

The subprocess.CalledProcessError is raised when a subprocess command exits with a non-zero return code. It contains information about the command that was executed, the return code, and the output/error messages generated by the command.

The basic syntax for handling the subprocess.CalledProcessError is as follows:

import subprocess

try:
    output = subprocess.check_output(command, shell=True)
except subprocess.CalledProcessError as e:
    print(f"Command '{e.cmd}' failed with return code {e.returncode}")
    print(f"Error message: {e.output.decode()}")

In the above code snippet, we use the check_output() function from the subprocess module to run the command. If the command exits with a non-zero return code, a subprocess.CalledProcessError is raised. We can then catch this exception, access details such as the command, return code, and error message, and handle them accordingly.

Handling subprocess.CalledProcessError

When handling the subprocess.CalledProcessError, we can take various actions based on the specific requirements of our program. Some common approaches include:

1. Printing the error details and exiting

import subprocess
import sys

try:
    output = subprocess.check_output(command, shell=True)
except subprocess.CalledProcessError as e:
    print(f"Command '{e.cmd}' failed with return code {e.returncode}")
    print(f"Error message: {e.output.decode()}")
    sys.exit(1)  # Exit the program with a non-zero status code

In this approach, we print the error details and use sys.exit() to exit the program. By using a non-zero status code (typically 1), we indicate that an error has occurred.

2. Retry the command

import subprocess
import time

max_retries = 3
retry_delay = 5

for _ in range(max_retries):
    try:
        output = subprocess.check_output(command, shell=True)
        break  # Exit the loop if the command is successful
    except subprocess.CalledProcessError as e:
        print(f"Command '{e.cmd}' failed with return code {e.returncode}")
        print(f"Error message: {e.output.decode()}")
        print("Retrying...")
        time.sleep(retry_delay)
else:
    print(f"Command '{command}' failed after {max_retries} retries. Exiting.")
    sys.exit(1)  # Exit the program if all retries fail

In this approach, we define a maximum number of retries and a delay between retries. We use a loop to attempt running the command multiple times until it is successful or the maximum number of retries is reached. This can be useful in scenarios where intermittent failures are expected.

3. Gracefully handle the error and continue

import subprocess

try:
    output = subprocess.check_output(command, shell=True)
except subprocess.CalledProcessError as e:
    print(f"Command '{e.cmd}' failed with return code {e.returncode}")
    print(f"Error message: {e.output.decode()}")
    # Continue with the program logic, handling the error gracefully
    handle_error(e)

In this approach, we catch the subprocess.CalledProcessError and continue with the program logic, handling the error gracefully. This allows the program to recover from the error and continue its execution.

Conclusion

The subprocess.CalledProcessError exception provides a way to handle errors when running subprocess commands in Python. By using appropriate exception handling techniques, we can gracefully handle errors, print error details, retry commands, or continue with the program logic based on the specific requirements of our application.

Remember to always handle exceptions robustly in your code to ensure that your program behaves correctly, even in the face of unexpected errors generated by external commands.