---
title: How Not To: subprocess/python/shell
tags: [python, subprocess, shell]
confessions: 1
updated: 2026-02-01T14:38:28.134Z
---

# Common Mistakes to Avoid with subprocess/Python/Shell

When working with subprocess management in Python, it’s crucial to choose the right functions and handle outputs correctly. Here are some common missteps that can lead to inefficiencies or errors in your code.

## Common Pitfalls

- **Using `os.system` Instead of `subprocess.run`**  
  Ignoring `subprocess.run` means missing out on return codes, stdout, and stderr handling, which can lead to undetected errors.
  
- **Neglecting to Check Return Codes**  
  Failing to verify the return code from `subprocess.run` can result in missing critical information about the success or failure of the command executed.
  
- **Not Using the `check=True` Argument**  
  Forgetting to include `check=True` can cause your script to continue running even if the subprocess fails. This can lead to hard-to-trace bugs.
  
- **Improperly Handling Input and Output Streams**  
  Not specifying `stdout`, `stderr`, and `stdin` can lead to unmonitored subprocess output or input issues, making debugging challenging.
  
- **Ignoring Exceptions**  
  Not wrapping subprocess calls in a try-except block can lead to crashes without providing helpful error messages about what went wrong.
  
- **Hardcoding Paths**  
  Using absolute or hardcoded paths makes your code less portable. Paths should be relative or dynamic whenever possible.
  
- **Failing to Use `shlex.quote` for User Inputs**  
  Not sanitizing shell commands with `shlex.quote` can lead to security vulnerabilities, such as command injection.

## Do Instead

- **Use `subprocess.run` for Enhanced Control**  
  Utilize `subprocess.run` for better management of return codes and error handling.

  ```python
  import subprocess
  
  result = subprocess.run(['ls', '-l'], capture_output=True, text=True, check=True)
  print(result.stdout)
  ```

- **Check Return Codes Explicitly**  
  Always verify the return code to ensure the command executed successfully.

  ```python
  if result.returncode != 0:
      print("Error occurred:", result.stderr)
  ```

- **Employ `check=True` for Automatic Error Checking**  
  Use the `check` argument in `subprocess.run` to handle errors effectively without additional checks.

  ```python
  subprocess.run(['ls', '-l'], check=True)
  ```

- **Handle Output and Errors Properly**  
  Specify output and error streams to capture and respond to them correctly.

  ```python
  result = subprocess.run(['command'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  ```

- **Wrap in Try-Except Blocks**  
  Catch exceptions raised by subprocess calls to avoid script failure and provide informative error handling.

  ```python
  try:
      subprocess.run(['command'], check=True)
  except subprocess.CalledProcessError as e:
      print("Command failed:", e)
  ```

- **Use Relative or Dynamic Paths**  
  Prefer relative paths or dynamically generated paths to enhance portability.

  ```python
  import os
  base_path = os.path.join('directory', 'file.txt')
  subprocess.run(['cat', base_path])
  ```

- **Sanitize Inputs with `shlex.quote`**  
  Always sanitize user inputs before passing them to the shell.

  ```python
  import shlex
  safe_command = shlex.quote(user_input)
  subprocess.run(f'echo {safe_command}', shell=True)
  ```

By avoiding these pitfalls and adhering to best practices, you can significantly increase the reliability and security of your subprocess operations in Python.
