我想编写一个函数,该函数将执行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 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
该check_output
功能适用于仍在广泛使用的几乎所有版本的Python(2.7+)。2但对于较新的版本,不再推荐使用此方法。
现代版本的Python(3.5或更高版本): run
如果你使用的是Python 3.5或更高版本,并且不需要向后兼容,则建议使用新run功能。它为该subprocess
模块提供了非常通用的高级API 。要捕获程序的输出,请将subprocess.PIPE
标志传递给stdout关键字参数。然后访问stdout返回CompletedProcess
对象的属性:
>>> 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'
返回值是一个bytes对象,因此,如果你需要正确的字符串,则需要decode它。假设被调用的进程返回一个UTF-8编码的字符串:
>>> 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']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
你可以通过传递stderr=subprocess.PIPE
(捕获到result.stderr
)或stderr=subprocess.STDOUT
(捕获到result.stdout
常规输出)来捕获错误。如果不考虑安全性,你还可以shell=True
按照下面的说明通过传递来运行更复杂的Shell命令。
与旧的工作方式相比,这仅增加了一点复杂性。但是我认为值得这样做:现在,你仅需使用该run功能就可以完成几乎所有需要做的事情。
如果你使用的是旧版本的Python,或者需要适度的向后兼容性,则可以使用check_output上面简要介绍的函数。自python 2.7开始可用。
subprocess.check_output(*popenargs, **kwargs)
它采用与Popen(请参见下文)相同的参数,并返回一个包含程序输出的字符串。该答案的开头有一个更详细的用法示例。在Python 3.5及更高版本中,check_output
等效于run使用check=True
和stdout=PIPE
,仅返回stdout属性。
你可以通过stderr=subprocess.STDOUT
确保错误信息包含在返回的输出-但在Python中通过一些版本stderr=subprocess.PIPE
,以check_output
可引起死锁。如果不考虑安全性,你还可以shell=True
按照下面的说明通过传递来运行更复杂的Shell命令。
如果你需要通过管道stderr传递输入或将输入传递给流程,check_output则将无法完成任务。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('foo\nfoofoo\n')
>>> print out
foofoo
注艾伦·霍尔的回答,这表明在某些系统上,你可能需要设置stdout
,stderr
以及stdin所有PIPE(或DEVNULL)得到communicate
工作的。
在极少数情况下,你可能需要复杂的实时输出捕获。Vartec
的答案提出了一条前进的道路,但是communicate
如果不谨慎使用,则其他方法都容易出现死锁。
与上述所有功能一样,当不考虑安全性时,可以通过传递运行更复杂的Shell命令shell=True。
笔记
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中返回一个字符串,但bytes
在Python 3中返回一个对象。如果还没有,则花一点时间来学习unicode
。
问题内容: 我的最终目标是捕获终端中执行的上一条命令。由于〜/ .bash_history不包含当前终端会话中的命令,因此我不能简单地读取该文件。 在另一个线程中,我找到了以下脚本: 这与我要查找的内容非常接近,但是由于它是作为子进程启动的,因此它也不会包括当前终端会话的历史记录。有什么办法可以在当前shell中执行类似的命令? 问题答案: 为什么不直接读取文件。 〜/ .bash_history
问题内容: 在node.js中,我想找到一种方法来获取Unix终端命令的输出。有什么办法吗? 问题答案: 那就是我现在正在工作的项目中这样做的方式。 示例:检索git用户
问题内容: 我遇到了一个困扰我几天的问题。我在Python 2.7.10中使用了Paramiko模块,我想向Brocade路由器发出多个命令,但仅返回给定命令之一的输出,如下所示: 如果要打印完整的输出,它将包含发布到路由器的所有内容,但是我只想查看show命令的输出。 谁能解决这个问题? 我想问的最后一件事。我想过滤变量并检查是否出现诸如“ up”或“ down”之类的字符串,但是由于输出中的所
问题内容: 尝试读取的版本号时,我得到了很多其他行,需要忽略。我尝试阅读的手册,并尝试了以下命令: 我想知道这是否正确吗? 问题答案: 是的,这是从命令获取第一行输出的一种方法。 如果命令以相同的方式输出任何您想要捕获的标准错误,则需要将命令的标准错误重定向到标准输出流: 捕获第一行的方法还有很多,包括(在第一行之后退出),(仅打印第一行,但读取所有内容),(仅打印第一行,但再次读取所有内容)等。
我想知道这是不是正确的做法?
在一个节点中。js,我想找到一种获取Unix终端命令输出的方法。有没有办法做到这一点?