在所有官方维护的Python版本中,最简单的方法是使用subprocess.check_output
函数:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
运行仅将参数作为输入的单个程序。1 它返回的结果与打印到 的结果完全相同。如果需要将输入写入 ,请跳到 或 部分。如果要执行复杂的 shell 命令,请参阅本答案末尾的注释。stdout
stdin
run
Popen
shell=True
该函数适用于所有官方维护的Python版本。但对于更新的版本,可以使用更灵活的方法。check_output
Python的现代版本(3.5或更高版本):run
如果您使用的是Python 3.5 +,并且不需要向后兼容性,则官方文档建议将新的run
函数用于大多数任务。它为子流程
模块提供了一个非常通用的高级 API。若要捕获程序的输出,请将该标志传递给关键字参数。然后访问返回的已完成进程
对象的属性:subprocess.PIPE
stdout
stdout
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
返回值是一个对象,因此,如果您想要一个正确的字符串,则需要它。假设被调用的进程返回 UTF-8 编码的字符串:bytes
decode
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
如果需要,这都可以压缩为单行:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
如果要将输入传递给进程的 ,则可以将对象传递给关键字参数:stdin
bytes
input
>>> cmd = ['awk', 'length($0) > 5']
>>> ip = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip)
>>> result.stdout.decode('utf-8')
'foofoo\n'
您可以通过传递(捕获到 )或(捕获到以及常规输出)来捕获错误。如果要在进程返回非零退出代码时引发异常,可以传递 。(或者您可以检查上述属性。当安全性不是问题时,您还可以通过传递来运行更复杂的 shell 命令,如本答案末尾所述。stderr=subprocess.PIPE
result.stderr
stderr=subprocess.STDOUT
result.stdout
run
check=True
returncode
result
shell=True
更高版本的Python进一步简化了上述内容。在Python 3.7+中,上面的单行可以拼写如下:
>>> subprocess.run(['ls', '-l'], capture_output=True, text=True).stdout
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
与旧的做事方式相比,使用这种方式只会增加一点复杂性。但是现在,您几乎可以单独使用该功能执行任何需要执行的操作。run
run
旧版本的 Python (3-3.4):更多关于check_output
如果您使用的是较旧版本的Python,或者需要适度的向后兼容性,则可以使用上面简要描述的函数。它从Python 2.7开始可用。check_output
subprocess.check_output(*popenargs, **kwargs)
它采用与(见下文)相同的参数,并返回一个包含程序输出的字符串。这个答案的开头有一个更详细的用法示例。在 Python 3.5+ 中,等效于使用 和 执行 ,并仅返回属性。Popen
check_output
run
check=True
stdout=PIPE
stdout
您可以传递以确保错误消息包含在返回的输出中。当安全性不是问题时,您还可以通过传递来运行更复杂的 shell 命令,如本答案末尾所述。stderr=subprocess.STDOUT
shell=True
如果您需要通过管道将输入从流程传递到流程,则无法胜任该任务。在这种情况下,请参阅下面的示例。stderr
check_output
Popen
复杂的应用程序和Python的旧版本(2.6及以下):Popen
如果您需要深度向后兼容性,或者需要比 或 提供更复杂的功能,则必须直接使用对象,这些对象封装了子进程的低级 API。check_output
run
Popen
构造函数接受不带参数的单个命令,或者接受包含命令的列表作为其第一项,后跟任意数量的参数,每个参数作为列表中的单独项。shlex.split
可以帮助将字符串解析为格式适当的列表。 对象还接受用于进程 IO 管理和低级配置的大量不同参数。Popen
Popen
发送输入和捕获输出,几乎总是首选方法。如:communicate
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
或
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
如果设置 ,还允许您通过以下方式将数据传递给流程:stdin=PIPE
communicate
stdin
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
注意 Aaron Hall 的答案,它表明在某些系统上,您可能需要设置 、 和 所有设置为 (or) 才能开始工作。stdout
stderr
stdin
PIPE
DEVNULL
communicate
在极少数情况下,您可能需要复杂的实时输出捕获。Vartec的答案提出了一条前进的道路,但是如果不小心使用,其他方法很容易陷入僵局。communicate
与上述所有函数一样,当安全性不是问题时,可以通过传递来运行更复杂的shell命令。shell=True
笔记
1. 运行 shell 命令:shell=True
参数
通常,对 、 或 构造函数的每次调用都执行单个程序。这意味着没有花哨的bash风格的管道。如果要运行复杂的 shell 命令,可以传递 所有三个函数都支持 。例如:run
check_output
Popen
shell=True
>>> subprocess.check_output('cat books/* | wc', shell=True, text=True)
' 1299377 17005208 101299376\n'
但是,这样做会引起安全问题。如果您要执行的不仅仅是轻量级脚本编写,则最好单独调用每个进程,并将每个进程的输出作为输入传递给下一个进程,通过
run(cmd, [stdout=etc...], input=other_output)
或
Popen(cmd, [stdout=etc...]).communicate(other_output)
直接连接管道的诱惑很强;抵制它。否则,您可能会看到死锁或不得不做这样的事情。