How to Suppress Subprocess Output in Python

Have you ever run a Python script that calls external programs, only to have your console flooded with unwanted output? This is a common frustration when working with Python’s subprocess module.

While the subprocess module provides powerful functionality for interacting with external programs, managing the output of these programs can sometimes be challenging.

In this comprehensive guide, I’ll explore several methods to suppress or redirect the output from subprocess calls in Python. Whether you’re developing scripts that need to run silently in the background or just want to keep your console clean while running external commands, this article will provide you with the solutions you need.

Understanding the Problem

When calling external programs using Python’s subprocess module, these programs often produce standard output (stdout) and standard error (stderr) messages. While these messages can be useful for debugging, they can also clutter your console and make it difficult to read your own program’s output.

Consider this simple example where we use the espeak text-to-speech program:

import subprocess

text = ‘Hello World.’

print(text)

subprocess.call([‘espeak’, text])

Read: Linux Processes: A Beginner’s Guide to Understanding & Management

Though the espeak command works correctly, it might produce unwanted error messages or output that clutters your console. These messages can make it difficult to see your program’s own output (the printed “Hello World.” text in this case).

Solution 1: Using Python 3.3+ with subprocess.DEVNULL

If you’re using Python 3.3 or later, the most elegant solution is to use the built-in subprocess.DEVNULL constant, which represents the null device (/dev/null on Unix or NUL on Windows).

import subprocess

text = ‘Hello World.’

print(text)

subprocess.call([‘espeak’, text], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

 

This redirects both standard output and standard error to the null device, effectively silencing all output from the subprocess.

How it works:

  • stdout=subprocess.DEVNULL redirects standard output to the null device
  • stderr=subprocess.STDOUT redirects standard error to the same place as standard output (which in this case is the null device)

Read: Differences between a thread and a process

Solution 2: For Python 2.7 or Earlier Versions

If you’re using Python 2.7 or an earlier version that doesn’t have subprocess.DEVNULL, you can create your own null device file object:

import os

import subprocess

FNULL = open(os.devnull, ‘w’)

text = ‘Hello World.’

print(text)

subprocess.call([‘espeak’, text], stdout=FNULL, stderr=subprocess.STDOUT)

FNULL.close()  # Don’t forget to close the file when you’re done

In this approach, we:

  1. Open the null device (os.devnull) as a writable file
  2. Redirect both stdout and stderr to this file
  3. Close the file after we’re done to avoid resource leaks

You could also use a context manager to ensure the file is properly closed:

import os

import subprocess

text = ‘Hello World.’

print(text)

with open(os.devnull, ‘w’) as FNULL:

    subprocess.call([‘espeak’, text], stdout=FNULL, stderr=subprocess.STDOUT)

Read: Environment Variables in Python

Solution 3: Using subprocess.check_output()

Another approach, introduced in Python 2.7, is to use subprocess.check_output(). This function captures the output as a return value rather than displaying it:

import subprocess

text = ‘Hello World.’

print(text)

try:

    output = subprocess.check_output([‘espeak’, text], stderr=subprocess.STDOUT)

    # You can use ‘output’ if needed, or simply ignore it

except subprocess.CalledProcessError:

    # Handle any errors that might occur during execution

    pass

The benefit of this approach is that it not only suppresses the output but also makes it available for your program to use if needed. Additionally, check_output() will raise a CalledProcessError exception if the command fails, allowing you to handle errors more gracefully.

Solution 4: A Cross-Compatible Approach

If you need a solution that works across different Python versions, you might consider this more portable approach:

import subprocess

from subprocess import PIPE, STDOUT

# Try to import DEVNULL from subprocess if available (Python 3.3+)

try:

    from subprocess import DEVNULL

except ImportError:

    # Fall back to using os.devnull if DEVNULL is not available

    import os

    DEVNULL = open(os.devnull, ‘wb’)

text = ‘Hello World.’

print(text)

# For Python 3, encode the text if passing to stdin

if hasattr(text, ‘encode’):

    text = text.encode(‘utf-8’)

p = subprocess.Popen([‘espeak’], stdin=PIPE, stdout=DEVNULL, stderr=STDOUT)

p.communicate(text)

# Close DEVNULL if it’s a file object we created

if hasattr(DEVNULL, ‘close’):

    DEVNULL.close()

This approach has the advantage of being compatible with both Python 2 and 3, handling text encoding differences, and properly managing resources.

Understanding Redirection Options

When redirecting subprocess output, it’s important to understand the different options available:

  1. Redirecting stdout only: stdout=subprocess.DEVNULL 
    • Only the standard output is suppressed; error messages will still appear
  2. Redirecting stderr only: stderr=subprocess.DEVNULL 
    • Only error messages are suppressed; standard output will still appear
  3. Redirecting both independently: stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL 
    • Both standard output and error messages are suppressed independently
  4. Redirecting stderr to stdout: stderr=subprocess.STDOUT 
    • Error messages go to the same place as standard output
    • Often combined with redirection of stdout: stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
  5. Capturing output: stdout=subprocess.PIPE 
    • Output is captured rather than displayed
    • Must be used with p.communicate() to avoid potential deadlocks

Best Practices and Considerations

When suppressing subprocess output, keep these best practices in mind:

1. Resource Management

Always close file handles when you’re done with them to avoid resource leaks. The best approach is to use context managers (the with statement) whenever possible:

with open(os.devnull, ‘w’) as devnull:

    subprocess.call([‘espeak’, text], stdout=devnull, stderr=subprocess.STDOUT)

Read: Mastering Python Virtual Environments: A Comprehensive Guide to venv, pipenv, poetry, and More

2. Error Handling

Even if you’re suppressing output, you should still handle potential errors from the subprocess. The return code from subprocess.call() or exceptions from subprocess.check_output() provide valuable information:

try:

    result = subprocess.call([‘espeak’, text], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

    if result != 0:

        print(f”Command failed with return code {result}”)

except Exception as e:

    print(f”An error occurred: {e}”)

3. Selective Suppression

Consider whether you need to suppress both stdout and stderr. In some cases, you might want to keep error messages visible while suppressing normal output:

# Suppress only stdout, keep stderr visible

subprocess.call([‘espeak’, text], stdout=subprocess.DEVNULL)

# Suppress only stderr, keep stdout visible

subprocess.call([‘espeak’, text], stderr=subprocess.DEVNULL)

4. When Not to Suppress Output

While suppressing output can keep your console clean, it can also hide valuable information. During development or when debugging, consider keeping the output visible or redirecting it to a log file instead of discarding it completely.

Advanced Techniques

Redirecting to a Log File

Instead of completely discarding the output, you might want to redirect it to a log file:

with open(‘subprocess_log.txt’, ‘w’) as logfile:

    subprocess.call([‘espeak’, text], stdout=logfile, stderr=subprocess.STDOUT)

This approach maintains a record of the subprocess output while keeping your console clean.

Using the subprocess.run() Function (Python 3.5+)

In Python 3.5 and later, the subprocess.run() function provides a more convenient interface:

import subprocess

text = ‘Hello World.’

print(text)

completed_process = subprocess.run([‘espeak’, text], 

                                   stdout=subprocess.DEVNULL, 

                                   stderr=subprocess.DEVNULL,

                                   check=False)

The run() function returns a CompletedProcess object that contains information about the completed process, including return code and captured output (if any).

Frequently Asked Questions

How do I suppress output only if the command succeeds?

You can use a try-except block with check_output():

try:

    subprocess.check_output([‘espeak’, text], stderr=subprocess.STDOUT)

except subprocess.CalledProcessError as e:

    # Display the output only if there was an error

    print(f”Command failed with output: {e.output.decode()}”)

Can I temporarily suppress output and then restore it?

Yes, you can redirect output and then restore it. This is more complex but can be done by temporarily redirecting system stdout and stderr:

import sys

import os

import subprocess

# Save the original stdout and stderr

original_stdout = sys.stdout

original_stderr = sys.stderr

# Redirect to devnull

with open(os.devnull, ‘w’) as devnull:

    sys.stdout = devnull

    sys.stderr = devnull

    # Run your subprocess

    subprocess.call([‘espeak’, ‘Hello World.’])

    # Restore original stdout and stderr

    sys.stdout = original_stdout

    sys.stderr = original_stderr

print(“This will appear in the console”)

How do I suppress output when using shell=True?

When using shell=True, the same redirection techniques apply:

import subprocess

subprocess.call(‘espeak “Hello World”‘, 

                shell=True, 

                stdout=subprocess.DEVNULL, 

                stderr=subprocess.STDOUT)

Why am I still seeing output even after redirecting to DEVNULL?

This could happen for several reasons:

  1. The program might be bypassing standard output/error channels
  2. You might be redirecting only stdout but not stderr (or vice versa)
  3. If using Popen with stdout=PIPE or stderr=PIPE, you must call communicate()

Make sure you’re redirecting both stdout and stderr:

subprocess.call([‘espeak’, text], 

                stdout=subprocess.DEVNULL, 

                stderr=subprocess.DEVNULL)

Conclusion

Suppressing output from subprocess calls in Python is a common requirement when creating clean, user-friendly scripts. By using the techniques described in this article, you can control what output is displayed, captured, or discarded, making your Python scripts more professional and easier to use.

Whether you’re using the modern subprocess.DEVNULL approach in Python 3 or creating your own null device file in Python 2, the principles remain the same. With proper error handling and resource management, you can create robust scripts that interact with external programs without cluttering your console.


If you like the content, we would appreciate your support by buying us a coffee. Thank you so much for your visit and support.

 

Nikolaus Oosterhof

Nikolaus holds a degree in software development and has a strong passion for all things tech-related, especially gadgets with screens. Though he is nostalgic for older phone models, he's a retired gamer and continues to enjoy programming in open-source environments. Additionally, Nikolaus enjoys writing about Linux, macOS and Windows and has experience designing web pages.

Leave a Reply