从Python运行shell命令并捕获输出
我想编写一个函数来执行一个shell命令并将其输出作为一个字符串返回,不管它是错误还是成功消息。 我只想得到和命令行一样的结果。
什么是可以做这种事情的代码示例?
例如:
def run_command(cmd):
# ??????
print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'
这个问题的答案取决于你使用的Python版本。 最简单的方法是使用subprocess.check_output
函数:
>>> subprocess.check_output(['ls', '-l'])
b'total 0n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 filesn'
check_output
运行一个只有参数作为输入的程序。它返回的结果与打印到stdout
的结果完全相同。 如果您需要将输入写入stdin
,请跳至run
或Popen
部分。 如果您想执行复杂的shell命令,请参阅此答案结尾处关于shell=True
的注释。
check_output
函数几乎适用于所有仍在广泛使用的Python版本(2.7 +)。2但是对于更新的版本,它不再是推荐的方法。
现代版本的Python(3.5或更高版本): run
如果您使用Python 3.5或更高版本,并且不需要向后兼容性 ,则建议使用新的run
功能。 它为subprocess
模块提供了一个非常通用的高级API。 要捕获程序的输出,请将subprocess.PIPE
标志传递给stdout
关键字参数。 然后访问返回的CompletedProcess
对象的stdout
属性:
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 filesn'
返回值是一个bytes
对象,所以如果你想要一个正确的字符串,你需要decode
它。 假设被调用的进程返回一个UTF-8编码的字符串:
>>> result.stdout.decode('utf-8')
'total 0n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 filesn'
这可以全部压缩为一行:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 filesn'
如果要将输入传递给进程的stdin
,请将一个bytes
对象传递给input
关键字参数:
>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foonfoofoon'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoon'
您可以通过传递stderr=subprocess.PIPE
(捕获到result.stderr
)或stderr=subprocess.STDOUT
(捕获到result.stdout
以及常规输出)来捕获错误。 如果不担心安全问题,则还可以通过传递shell=True
来运行更复杂的shell命令,如下面的注释中所述。
与旧的做事方式相比,这增加了一点复杂性。 但我认为这是值得的回报:现在,你几乎可以做任何你需要做的run
功能。
较早版本的Python(2.7-3.4): check_output
如果您使用的是旧版本的Python,或者需要适度的向后兼容性,则可以使用check_output
函数,如上所述。 自从Python 2.7以来它已经可用。
subprocess.check_output(*popenargs, **kwargs)
它采用与Popen
相同的参数(见下文),并返回一个包含程序输出的字符串。 这个答案的开头有一个更详细的使用例子。
您可以传递stderr=subprocess.STDOUT
以确保返回的输出中包含错误消息 - 但不要将stderr=subprocess.PIPE
check_output
传递给check_output
。 它可能导致死锁。 如果不担心安全问题,则还可以通过传递shell=True
来运行更复杂的shell命令,如下面的注释中所述。
如果您需要从stderr
管道或将输入传递给进程, check_output
将不会完成任务。 在这种情况下请看下面的Popen
例子。
Python的复杂应用程序和旧版本(2.6及更低版本): Popen
如果您需要深度向后兼容性,或者您需要比check_output
提供的功能更复杂的功能,则必须直接使用Popen
对象,这些对象封装了子流程的低级API。
Popen
构造函数接受一个没有参数的单个命令 ,或一个包含一个命令作为其第一个项目的列表 ,然后是任意数量的参数,每个参数都作为列表中的一个单独的项目。 shlex.split
可以帮助将字符串解析为适当格式的列表。 Popen
对象也接受许多用于进程IO管理和低级配置的不同参数。
要发送输入和捕获输出, 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('foonfoofoon')
>>> print out
foofoo
注意Aaron Hall的回答,这表明在某些系统上,您可能需要将stdout
, stderr
和stdin
全部设置为PIPE
(或DEVNULL
)才能使communicate
正常工作。
在极少数情况下,您可能需要复杂的实时输出捕获。 Vartec的答案提出了一条前进的道路,但除communicate
之外的其他方法如果不谨慎使用,则容易出现死锁。
与所有上述函数一样,当安全性不是问题时,您可以通过传递shell=True
来运行更复杂的shell命令。
笔记
1.运行shell命令: shell=True
参数
通常情况下,每次调用run
, check_output
,或Popen
构造函数执行一个程序。 这意味着没有花哨的bash式管道。 如果你想运行复杂的shell命令,你可以传递shell=True
,这三个函数都支持。
但是,这样做会引起安全问题。 如果你所做的不仅仅是轻脚本,你最好单独调用每个进程,并将每个进程的输出作为输入传递给下一个,通过
run(cmd, [stdout=etc...], input=other_output)
要么
Popen(cmd, [stdout=etc...]).communicate(other_output)
直接连接管道的诱惑力很强。 抵制它。 否则,你可能会看到僵局或必须做这样的黑客事情。
2. Unicode考虑
check_output
在Python 2中返回一个字符串,但是在Python 3中返回一个bytes
对象。如果你还没有学习unicode,值得花一点时间。
这很容易,但只适用于Unix(包括Cygwin)。
import commands
print commands.getstatusoutput('wc -l file')
它返回一个元组(返回值,输出)
类似的东西:
def runProcess(exe):
p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while(True):
retcode = p.poll() #returns None while subprocess is running
line = p.stdout.readline()
yield line
if(retcode is not None):
break
请注意,我将stderr重定向到stdout,它可能不是您想要的,但我也想要错误消息。
这个函数在它们到来时一行一行地产生 (通常你必须等待子进程完成才能获得输出)。
对于你的情况,它的用法是:
for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
print line,
链接地址: http://www.djcxy.com/p/4317.html
上一篇: Running shell command from Python and capturing the output