【发布时间】:2010-11-27 12:19:45
【问题描述】:
在 Python 中的 Ruby 和 Perl 中的反引号是什么?也就是说,在 Ruby 中我可以这样做:
foo = `cat /tmp/baz`
Python 中的等效语句是什么样的?我已经尝试过os.system("cat /tmp/baz"),但这会将结果置于标准输出并返回给我该操作的错误代码。
【问题讨论】:
在 Python 中的 Ruby 和 Perl 中的反引号是什么?也就是说,在 Ruby 中我可以这样做:
foo = `cat /tmp/baz`
Python 中的等效语句是什么样的?我已经尝试过os.system("cat /tmp/baz"),但这会将结果置于标准输出并返回给我该操作的错误代码。
【问题讨论】:
output = os.popen('cat /tmp/baz').read()
【讨论】:
`...`(捕获标准输出,传递标准错误)——除了一个例外:Ruby 允许在事后通过$? 确定进程的退出代码;在 Python 中,据我所知,您必须为此使用 subprocess 模块的函数。
最灵活的方式是使用subprocess模块:
import subprocess
out = subprocess.run(["cat", "/tmp/baz"], capture_output=True)
print("program output:", out)
capture_output 是在 Python 3.7 中引入的,对于旧版本,可以使用特殊函数 check_output() 代替:
out = subprocess.check_output(["cat", "/tmp/baz"])
如果需要细粒度控制,也可以手动构造子流程对象:
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()
所有这些函数都支持keyword parameters 来自定义子流程的执行方式。例如,您可以使用 shell=True 通过 shell 执行程序,如果您需要 * 的文件名扩展之类的东西,但 limitations 附带。
【讨论】:
Popen() 提供的灵活性,文档推荐 subprocess.run()(我不知道是否值得)。
sth is right。您也可以使用 os.popen(),但在可用的情况下(Python 2.4+)子进程通常更可取。
但是,与一些鼓励它的语言不同,通常认为生成一个子进程是不好的形式,您可以在该语言中执行相同的工作。它更慢、更不可靠并且依赖于平台。你的例子会更好:
foo= open('/tmp/baz').read()
埃塔:
baz 是一个目录,我正在尝试获取该目录中所有文件的内容
?目录上的 cat 让我出错。
如果你想要一个文件列表:
import os
foo= os.listdir('/tmp/baz')
如果您想要目录中所有文件的内容,例如:
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)
或者,如果您可以确定其中没有目录,则可以将其放入单行中:
path= '/tmp/baz'
foo= ''.join(open(os.path.join(path, child), 'rb').read() for child in os.listdir(path))
【讨论】:
foo = subprocess.check_output(["cat", "/tmp/baz"])
【讨论】:
从 Python 3.5 开始,推荐使用subprocess.run。从 Python 3.7 开始,要获得与您描述的相同的行为,您将使用:
cpe = subprocess.run("ls", shell=True, capture_output=True)
这将返回一个subprocess.CompletedProcess 对象。到 stdout 的输出将在 cpe.stdout 中,到 stderr 的输出将在 cpe.stderr 中,它们都是 bytes 对象。您可以使用cpe.stdout.decode() 解码输出以获取str 对象,或者通过将text=True 传递给subprocess.run 来获取a:
cpe = subprocess.run("ls", shell=True, capture_output=True, text=True)
在后一种情况下,cpe.stdout 和 cpe.stderr 都是 str 对象。
【讨论】:
text=True 参数来获取 str 而不是字节。
最简单的方法是使用命令包。
import commands
commands.getoutput("whoami")
输出:
'bganesan'
【讨论】:
import os
foo = os.popen('cat /tmp/baz', 'r').read()
【讨论】:
我正在使用
(6:0)$ python --version Python 2.7.1
上面的一个例子是:
import subprocess
proc = subprocess.Popen(["cat", "/tmp/baz"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out
对我来说,这无法访问目录 /tmp。在查看了子进程的文档字符串后,我替换了
[“程序”,“arg”]
与
“程序参数”
并获得了所需的 shell 扩展行为(a la Perl 的 `prog arg`)
打印 subprocess.Popen("ls -ld /tmp/v*", stdout=subprocess.PIPE, shell=True).communicate()[0]
前段时间我放弃了使用 python,因为我对执行 perl `cmd ...` 的等效操作感到恼火。我很高兴发现 Python 让这变得合理。
【讨论】:
如果你使用 subprocess.Popen,记得指定 bufsize。默认为 0,表示“无缓冲”,而不是“选择合理的默认值”。
【讨论】:
这在 python3 中不起作用,但在 python2 中,您可以使用自定义 __repr__ 方法扩展 str,该方法调用您的 shell 命令并返回它,如下所示:
#!/usr/bin/env python
import os
class Command(str):
"""Call system commands"""
def __repr__(cmd):
return os.popen(cmd).read()
你可以像这样使用
#!/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`
【讨论】:
repr()Python 3 中的 backtick (`) 运算符 was removed。它与单引号令人困惑地相似,并且难以在某些键盘上键入。代替backtick,使用等效的内置函数repr()。
【讨论】: