Equivalent of Bash Backticks in Python

PythonBackticks

Python Problem Overview


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.

Python Solutions


Solution 1 - Python

output = os.popen('cat /tmp/baz').read()

Solution 2 - Python

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.

Solution 3 - Python

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

Solution 4 - Python

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

Solution 5 - Python

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.

Solution 6 - Python

Easiest way is to use commands package.

import commands

commands.getoutput("whoami")

Output:

> 'bganesan'

Solution 7 - Python

import os
foo = os.popen('cat /tmp/baz', 'r').read()

Solution 8 - Python

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.

Solution 9 - Python

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

Solution 10 - Python

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`

Solution 11 - Python

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChris BunchView Question on Stackoverflow
Solution 1 - PythonJohn KugelmanView Answer on Stackoverflow
Solution 2 - PythonsthView Answer on Stackoverflow
Solution 3 - PythonbobinceView Answer on Stackoverflow
Solution 4 - PythonjfsView Answer on Stackoverflow
Solution 5 - PythongerritView Answer on Stackoverflow
Solution 6 - PythonBalachander GanesanView Answer on Stackoverflow
Solution 7 - PythonawattsView Answer on Stackoverflow
Solution 8 - PythonfunkyjView Answer on Stackoverflow
Solution 9 - PythonGeorgeView Answer on Stackoverflow
Solution 10 - PythonThorSummonerView Answer on Stackoverflow
Solution 11 - PythonPedro LobitoView Answer on Stackoverflow