89

What is the equivalent of the backticks found in Ruby and Perl in Python? That is, in Ruby I can do this:

foo = `cat /tmp/baz`

What does the equivalent statement look like in Python? I've tried os.system("cat /tmp/baz") but that puts the result to standard out and returns to me the error code of that operation.

Sun
  • 1,505
  • 17
  • 25
Chris Bunch
  • 87,773
  • 37
  • 126
  • 127
  • http://stackoverflow.com/questions/2924310/whats-a-good-equivalent-to-pythons-subprocess-check-call-that-returns-the-conte – jfs Sep 19 '11 at 10:03

11 Answers11

112
output = os.popen('cat /tmp/baz').read()
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 4
    @mckenzm The question is about capturing the output of an external process. Capturing the output of a Python function would be a quite different question. – John Kugelman Jan 02 '15 at 05:17
  • 1
    Wonderfully concise, and indeed the equivalent of Ruby's `\`...\`` (capturing stdout, passsing stderr through) - with one exception: Ruby allows determining the process' exit code via`$?`after the fact; in Python, from what I can tell, you'll have to use the `subprocess` module's functions for that. – mklement0 Apr 09 '19 at 21:00
85

The most flexible way is to use the subprocess module:

import subprocess

out = subprocess.run(["cat", "/tmp/baz"], capture_output=True)
print("program output:", out)

capture_output was introduced in Python 3.7, for older versions the special function check_output() can be used instead:

out = subprocess.check_output(["cat", "/tmp/baz"])

You can also manually construct a subprocess object if you need fine grained control:

proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()

All these functions support keyword parameters to customize how exactly the subprocess is executed. You can for example use shell=True to execute the program through the shell, if you need things like file name expansions of *, but that comes with limitations.

sth
  • 222,467
  • 53
  • 283
  • 367
  • 2
    yes, this is the only sane way, you could wrap it in a function so you can call something like execute("command") – Vinko Vrsalovic Sep 11 '09 at 13:54
  • This actually doesn't work for me, as in this case, baz is a directory and I'm trying to get the contents of all the files in that directory. (doing cat /tmp/baz/* works in ticks but not via the method described here) – Chris Bunch Sep 11 '09 at 13:57
  • 6
    re: "*" does not work; use subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE, shell=True) instead. Since glob (star) expansion is handled by shell, subprocessing module must use shell expansion in this case (provided by /bin/sh). – Pasi Savolainen Sep 11 '09 at 14:03
  • you could use `subprocess.check_output()` http://stackoverflow.com/questions/236737/making-a-system-call-that-returns-the-stdout-output-as-a-string/236909#236909 – jfs Feb 04 '11 at 09:53
  • 1
    From http://docs.python.org/2/library/subprocess.html#popen-constructor : "(with shell=True) If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself." So, if you're going to use shell=True, then the first arg should probably be the string "cat /tmp/baz". Alternatively, if you want to use a sequence as the first arg then you should use shell=False – onlynone Jan 11 '13 at 18:04
  • I thought the question was for the python equivalent of backticks. This seems more like the python equivelent of `IO.popen() {}` – Jun-Dai Bates-Kobashigawa Sep 02 '14 at 10:49
  • 1
    @gerrit: it is not deprecated. The docs *recommend* `subprocess.run()` (I don't know whether it is deserved) if you don't need to support earlier versions or if you don't need the flexibility provided by `Popen()`. – jfs Mar 28 '16 at 04:05
28

sth is right. You can also use os.popen(), but where available (Python 2.4+) subprocess is generally preferable.

However, unlike some languages that encourage it, it's generally considered bad form to spawn a subprocess where you can do the same job inside the language. It's slower, less reliable and platform-dependent. Your example would be better off as:

foo= open('/tmp/baz').read()

eta:

baz is a directory and I'm trying to get the contents of all the files in that directory

? cat on a directory gets me an error.

If you want a list of files:

import os
foo= os.listdir('/tmp/baz')

If you want the contents of all files in a directory, something like:

contents= []
for leaf in os.listdir('/tmp/baz'):
    path= os.path.join('/tmp/baz', leaf)
    if os.path.isfile(path):
        contents.append(open(path, 'rb').read())
foo= ''.join(contents)

or, if you can be sure there are no directories in there, you could fit it in a one-liner:

path= '/tmp/baz'
foo= ''.join(open(os.path.join(path, child), 'rb').read() for child in os.listdir(path))
Community
  • 1
  • 1
bobince
  • 528,062
  • 107
  • 651
  • 834
  • 1
    Although this wasn't an answer to the question, it's the best answer for educating users. – noamtm Feb 28 '10 at 14:28
  • 1
    The question title is "what is the equivalent of backticks". I assumed that "cat" was just an example command. This answer does not help with the general case. – Jason Oct 22 '17 at 06:38
16
foo = subprocess.check_output(["cat", "/tmp/baz"])
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 3
    This is the most straightforward way now. "subprocess.check_output" was added in Python 2.7, which was released in July 2010, after the other "popen" answers were given. – Robert Fleming Apr 18 '13 at 19:27
12

From Python 3.5 onward, the recommended way is to use subprocess.run. Since Python 3.7, to get the same behaviour as you describe, you would use:

cpe = subprocess.run("ls", shell=True, capture_output=True)

This will return a subprocess.CompletedProcess object. The output to stdout will be in cpe.stdout, the output to stderr will be in cpe.stderr, which will both be bytes objects. You can decode the output to get a str object by using cpe.stdout.decode() or get a by passing text=True to subprocess.run:

cpe = subprocess.run("ls", shell=True, capture_output=True, text=True)

In the latter case, cpe.stdout and cpe.stderr are both str objects.

gerrit
  • 24,025
  • 17
  • 97
  • 170
  • 1
    From python 3.7 on you can use the `text=True` parameter to get back a str instead of bytes. – bwv549 Oct 12 '20 at 23:31
6

Easiest way is to use commands package.

import commands

commands.getoutput("whoami")

Output:

'bganesan'

3
import os
foo = os.popen('cat /tmp/baz', 'r').read()
awatts
  • 1,008
  • 8
  • 13
  • 3
    This is the equivalent of Ruby's backticks, but if your problem is to list the contents of a directory then this is not the best way to do it. – awatts Sep 11 '09 at 14:28
2

I'm using

(6:0)$ python --version Python 2.7.1

One of the examples above is:

import subprocess
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out

For me, this failed to access the directory /tmp. After looking at the doc string for subprocess I replaced

[ "prog", "arg"]

with

"prog arg"

and got the shell expansion behavior that was desired (a la Perl's `prog arg`)

print subprocess.Popen("ls -ld /tmp/v*", stdout=subprocess.PIPE, shell=True).communicate()[0]


I quit using python a while back because I was annoyed with the difficulty of of doing the equivalent of perl `cmd ...`. I'm glad to find Python has made this reasonable.

funkyj
  • 21
  • 2
1

If you use subprocess.Popen, remember to specify bufsize. The default is 0, which means "unbuffered", not "choose a reasonable default".

George
  • 3,027
  • 1
  • 24
  • 17
1

This will not work in python3, but in python2 you can extend str with a custom __repr__ method that calls your shell command and returns it like so:

#!/usr/bin/env python

import os

class Command(str):
    """Call system commands"""

    def __repr__(cmd):
        return os.popen(cmd).read()

Which you can use like

#!/usr/bin/env python
from command import Command

who_i_am = `Command('whoami')`

# Or predeclare your shell command strings
whoami = Command('whoami')
who_i_am = `whoami`
ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
-1

repr()

The backtick (`) operator was removed in Python 3. It is confusingly similar to a single quote, and hard to type on some keyboards. Instead of the backtick, use the equivalent built-in function repr().

Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268