145

From the examples in docs on subprocess.run() it seems like there shouldn't be any output from

subprocess.run(["ls", "-l"])  # doesn't capture output

However, when I try it in a python shell the listing gets printed. I wonder if this is the default behaviour and how to suppress the output of run().

10 Rep
  • 2,156
  • 7
  • 17
  • 31
planetp
  • 12,388
  • 16
  • 74
  • 140
  • 2
    http://stackoverflow.com/questions/8529390/is-there-a-quiet-version-of-subprocess-call – user2290362 Dec 15 '16 at 19:25
  • 2
    `subprocess.run()` doesn't capture stdout or stderr by default, to do so requires passing `PIPE`s for the `stdout` and/or `stderr` arguments (it's right in the linked documentation). So, unless you do, they will display as they normally would from the other process. – martineau Dec 15 '16 at 20:11
  • 3
    Do you want to suppress the output or capture it? – SethMMorton Dec 15 '16 at 20:27
  • @SethMMorton: right now I just need to hide it. – planetp Dec 15 '16 at 20:41
  • 13
    This question has been marked as a duplicate, but I think this is a mistake, because the API changed significantly between Python 2.7 (`process.call`), and Python 3.5 (`process.run`). I came here explicitly looking for the Python 3 answer to this question. The accepted answer for this question, and the top comment on it, are both more useful in that context than the answers on the other question. – GlennS Dec 17 '18 at 01:22
  • 8
    Since [Python 3.7](https://docs.python.org/3.7/library/subprocess.html) you can also just use the `capture_output=True` parameter. – Czechnology May 08 '19 at 16:42
  • 1
    Agree that this question shouldn't be marked as duplicated. `subprocess.run` is the only high-level API recommended in the subprocess module since Python 3.5. – Benjamin Du Aug 13 '19 at 21:24
  • What do y'all mean by capture? Where does the output go when I capture it? – Joooeey Sep 09 '21 at 08:06

2 Answers2

257

Here is how to suppress output, in order of decreasing levels of cleanliness. They assume you are on Python 3.

  1. You can redirect to the special subprocess.DEVNULL target.
import subprocess

subprocess.run(['ls', '-l'], stdout=subprocess.DEVNULL)
# The above only redirects stdout...
# this will also redirect stderr to /dev/null as well
subprocess.run(['ls', '-l'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# Alternatively, you can merge stderr and stdout streams and redirect
# the one stream to /dev/null
subprocess.run(['ls', '-l'], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
  1. If you want a fully manual method, can redirect to /dev/null by opening the file handle yourself. Everything else would be identical to method #1.
import os
import subprocess

with open(os.devnull, 'w') as devnull:
    subprocess.run(['ls', '-l'], stdout=devnull)

Here is how to capture output (to use later or parse), in order of decreasing levels of cleanliness. They assume you are on Python 3.

NOTE: The below examples use text=True.

  • This causes the STDOUT and STDERR to be captured as str instead of bytes.
    • Omit text=True to get bytes data
  • text=True is Python >= 3.7 only, use universal_newlines=True on Python <= 3.6
    • universal_newlines=True is identical to text=True but more verbose to type but should exist on all Python versions
  1. If you simply want to capture both STDOUT and STDERR independently, AND you are on Python >= 3.7, use capture_output=True.
import subprocess

result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)
print(result.stderr)
  1. You can use subprocess.PIPE to capture STDOUT and STDERR independently. This works on any version of Python that supports subprocess.run.
import subprocess

result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, text=True)
print(result.stdout)

# To also capture stderr...
result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(result.stdout)
print(result.stderr)

# To mix stdout and stderr into a single string
result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
print(result.stdout)
SethMMorton
  • 41,116
  • 12
  • 64
  • 80
  • 28
    Note that from Python ver. 3.3 there is actually a `subprocess.DEVNULL`, so `stdout` argument can be assigned directly without the `open`, just using `stdout=subprocess.DEVNULL`. – EquipDev Mar 24 '17 at 14:09
  • I'm getting `NameError: name 'devnull' is not defined` on Python 3.7 –  Sep 21 '19 at 03:00
  • 1
    @Sabrina Have you defined `devnull`? – SethMMorton Sep 21 '19 at 03:05
  • Is it possible to print the output while simultaneously capturing the data in a pipe (to use later or parse)? – Christopher Sep 23 '19 at 15:51
  • @Christopher If you don't care about printing while the program is running, you can just print `result.stdout` after-the-fact. If you want to capture and print real-time, it's a bit more complicated because you cannot use `subprocess.run`, you need the lower-level `subprocess.Popen`. I have used something [like this answer](https://stackoverflow.com/a/6414278/1399279) when I need to do that (adjust syntax from answer for Python 3). – SethMMorton Sep 23 '19 at 20:12
  • Note that despite your answer accidentally making it look like the opposite is true, your `subprocess.PIPE` examples above DO work with Python < 3.7, such as Python 3.6. – Gabriel Staples Jul 10 '20 at 22:41
  • I've edited your answer and noted that in your answer. – Gabriel Staples Jul 10 '20 at 22:43
  • Huh, I never would have read that as implying they did not work on < 3.7. But, I’m glad you made it that much clearer – SethMMorton Jul 10 '20 at 23:17
  • i;m only getting <_io.bufferedreader name="3"> as an output – greendino Oct 18 '20 at 21:45
  • i was runing my flask server in one subprocess in the bg and then starting tests in another subprocess but the outcome was a nightmare! doing subprocess.run(['my', 'process'], stdout=subprocess.DEVNULL) did let my server process work on the background while the second subprocess test run at the same time with out clogging the outputs/prints, and if something goes wrong with the first subprocess(the server) i will still get that print. super thanks for the examples! – pelos Jul 29 '21 at 22:49
18

ex: to capture the output of ls -a

import subprocess
ls = subprocess.run(['ls', '-a'], capture_output=True, text=True).stdout.strip("\n")
print(ls)
Shaeinst
  • 197
  • 1
  • 5
  • 4
    this works for python 3.7, though not for python 3.6 (I get `TypeError: __init__() got an unexpected keyword argument 'capture_output'`) – BCArg May 20 '21 at 09:36
  • the last part helps get a clean output to a variable. – Lambert Jan 19 '22 at 21:00