122

I want to run a command in pythong, using the subprocess module, and store the output in a variable. However, I do not want the command's output to be printed to the terminal. For this code:

def storels(): a = subprocess.Popen("ls",shell=True) storels() 

I get the directory listing in the terminal, instead of having it stored in a. I've also tried:

 def storels(): subprocess.Popen("ls > tmp",shell=True) a = open("./tmp") [Rest of Code] storels() 

This also prints the output of ls to my terminal. I've even tried this command with the somewhat dated os.system method, since running ls > tmp in the terminal doesn't print ls to the terminal at all, but stores it in tmp. However, the same thing happens.

Edit:

I get the following error after following marcog's advice, but only when running a more complex command. cdrecord --help. Python spits this out:

Traceback (most recent call last): File "./install.py", line 52, in <module> burntrack2("hi") File "./install.py", line 46, in burntrack2 a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE) File "/usr/lib/python2.6/subprocess.py", line 633, in __init__ errread, errwrite) File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory 
3
  • 2
    Just a note, using shell=true is discouraged in the Python docs. docs.python.org/2/library/… Commented Dec 9, 2013 at 16:13
  • Use this link https://stackoverflow.com/a/75175057/12780274 Commented Jan 19, 2023 at 16:04
  • At least I know I'm not the only one who types Pythong now and then... Commented Mar 18, 2024 at 20:38

3 Answers 3

169

To get the output of ls, use stdout=subprocess.PIPE.

>>> proc = subprocess.Popen('ls', stdout=subprocess.PIPE) >>> output = proc.stdout.read() >>> print output bar baz foo 

The command cdrecord --help outputs to stderr, so you need to pipe that indstead. You should also break up the command into a list of tokens as I've done below, or the alternative is to pass the shell=True argument but this fires up a fully-blown shell which can be dangerous if you don't control the contents of the command string.

>>> proc = subprocess.Popen(['cdrecord', '--help'], stderr=subprocess.PIPE) >>> output = proc.stderr.read() >>> print output Usage: wodim [options] track1...trackn Options: -version print version information and exit dev=target SCSI target to use as CD/DVD-Recorder gracetime=# set the grace time before starting to write to #. ... 

If you have a command that outputs to both stdout and stderr and you want to merge them, you can do that by piping stderr to stdout and then catching stdout.

subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

As mentioned by Chris Morgan, you should be using proc.communicate() instead of proc.read().

>>> proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) >>> out, err = proc.communicate() >>> print 'stdout:', out stdout: >>> print 'stderr:', err stderr:Usage: wodim [options] track1...trackn Options: -version print version information and exit dev=target SCSI target to use as CD/DVD-Recorder gracetime=# set the grace time before starting to write to #. ... 
Sign up to request clarification or add additional context in comments.

9 Comments

Alright, that works for 'ls', but later on I ran into a different problem, when trying to run a different command. When I try to run "cdrecord --help" with that method, I get a traceback error.
Thanks a ton!! That did it. If you don't mind me asking, how would you differentiate between using the stdout method and this stderr method?
@Insomaniacal In this case, I knew usage is generally dumped to stderr. But in general, a simple test is to cmd > /dev/null if you still see output it's going to stderr. Confirm by piping stderr cmd 2> /dev/null and it should vanish into /dev/null.
@Insomaniacal: in general stdout will be used, sometimes but sometimes stderr; in general, use stdout unless it doesn't work and then try stderr. I believe it can be arranged in some terminals to colour stderr differently so you can obviously tell.
Under Python3, output won't be a string, but a bytes sequence. Try output.decode(encoding='utf-8') or output.decode(encoding='latin-1') to obtain a string.
|
49

If you are using python 2.7 or later, the easiest way to do this is to use the subprocess.check_output() command. Here is an example:

output = subprocess.check_output('ls') 

To also redirect stderr you can use the following:

output = subprocess.check_output('ls', stderr=subprocess.STDOUT) 



In the case that you want to pass parameters to the command, you can either use a list or use invoke a shell and use a single string.

output = subprocess.check_output(['ls', '-a']) output = subprocess.check_output('ls -a', shell=True) 

5 Comments

This does not suppress output, as requested ("I do not want the command's output to be printed to the terminal").
This does suppress all output to the terminal for me (as long as I use the stderr=subprocess.STDOUT to capture both STDOUT and STDERR). Do you have an example command where it does not work?
Emre, I have seen this behavior with python 2.6
This also does not suppress output for me (using Python 3.9 and running an OpenSSL command)
This command only works in python2 it seems. In between python 3.6-3.12 versions it is only checking return code It returns 0 or raises CalledProcessError only. I've compared implementation of versions/3.6.15/lib/python3.6/subprocess.py and versions/3.12.2/lib/python3.12/subprocess.py through pyenv and they are identical. They both return the result of wait function, which is return code of process.
16

With a = subprocess.Popen("cdrecord --help",stdout = subprocess.PIPE) , you need to either use a list or use shell=True;

Either of these will work. The former is preferable.

a = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE) a = subprocess.Popen('cdrecord --help', shell=True, stdout=subprocess.PIPE) 

Also, instead of using Popen.stdout.read/Popen.stderr.read, you should use .communicate() (refer to the subprocess documentation for why).

proc = subprocess.Popen(['cdrecord', '--help'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.