Equivalent of Bash Backticks in Python

Question:

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.

Asked By: Chris Bunch

||

Answers:

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.

Answered By: sth
output = os.popen('cat /tmp/baz').read()
Answered By: John Kugelman
import os
foo = os.popen('cat /tmp/baz', 'r').read()
Answered By: awatts

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))
Answered By: bobince

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

Answered By: George

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.

Answered By: funkyj
foo = subprocess.check_output(["cat", "/tmp/baz"])
Answered By: jfs

Easiest way is to use commands package.

import commands

commands.getoutput("whoami")

Output:

‘bganesan’

Answered By: Balachander Ganesan

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`
Answered By: ThorSummoner

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.

Answered By: gerrit

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().

Answered By: Pedro Lobito
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.