文章目录
我想编写一个函数来执行一个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 运行一个只有参数作为输入的程序。 1 它返回的结果与打印到 stdout 完全一样。如果您需要将输入写入 stdin
,请跳到 run 或部分。如果您想执行复杂的shell命令,请参阅本答案末尾 shell = True `的注释。
check_output功能几乎适用于广泛使用的所有版本的Python(2.7 +)。 2 但是对于更新的版本,它不再是推荐的方法
Modern versions of Python (3.5 or higher): run
如果您使用 Python 3.5 或更高版本,并且 不需要向后兼容性 ,new run function。它为subprocess模块提供了一个非常通用的高级API。要捕获程序的输出,请将subprocess.PIPE标志传递给stdout关键字参数。然后访问返回的的stdout属性>
CompletedProcess `对象:
>>> 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(capture到result.stderr)或stderr =
subprocess.STDOUT到result.stdout以及常规输出)。如果不担心安全问题,则还可以通过传递shell = True来运行更复杂的shell命令,如下面的注释中所述。
与旧的做事方式相比,这增加了一点复杂性。但是我认为这是值得的:现在你几乎可以做任何事情,你需要做的就是run函数。
Older versions of 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
。它可能导致[死锁](http://docs.python.org/library/subprocess.html#subprocess.check_output)。如果不担心安全问题,则还可以通过传递shell = True `来运行更复杂的shell命令,如下面的注释中所述。
如果您需要从stderr进行管道输入或将输入传递给进程,则check_output将不能执行任务。在这种情况下,请参阅下面的Popen示例。
Complex applications & legacy versions of Python (2.6 and below): Popen
如果您需要深度向后兼容性,或者您需要比check_output提供的更复杂的功能,则必须直接使用Popen对象,这些对象封装了低子进程的API级别。
Popen 构造函数接受 **没有参数的单个命令** ,或 **列表** ,其中包含命令作为其第一项,各自作为列表中的单独项目。 [shlex.split ](https://docs.python.org/3/library/shlex.html)可以帮助将字符串解析为适当的格式名单。 Popen对象还接受一个[不同参数的主机< /进程IO管理和低级配置。
要发送输入和捕获输出,沟通几乎总是首选的方法。如:
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代码>来工作。
在极少数情况下,您可能需要复杂的实时输出捕获。 Vartec的答案提出了一个前进的方向,但通信以外的方法很容易发生死锁不要小心使用。
与所有上述函数一样,当安全性不是问题时,您可以通过传递shell = True来运行更复杂的shell命令。
Notes
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')
它返回一个带有(return_value,output)
的元组
未经作者同意,本文严禁转载,违者必究!