Python 中 Bash Backticks 的等价物

Ruby 和 Perl 中的反勾在 Python 中的等价物是什么?也就是说,在 Ruby 中我可以这样做:

foo = `cat /tmp/baz`

在 Python 中等效的语句是什么样子的?我已经尝试了 os.system("cat /tmp/baz"),但它将结果标准化,并返回给我该操作的错误代码。

47851 次浏览

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.

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

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

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

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.

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

Easiest way is to use commands package.

import commands


commands.getoutput("whoami")

Output:

'bganesan'

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`

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.

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