我想编写一个函数来执行shell命令并返回其输出 as a string ,无论是错误还是成功消息 . 我只想获得与命令行相同的结果 .
什么是代码示例会做这样的事情?
例如:
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'
13 回答
在Python 3.5中:
Vartec's答案没有读取所有行,所以我做了一个版本:
用法与接受的答案相同:
您可以使用以下命令运行任何shell命令 . 我在ubuntu上使用过它们 .
您的里程可能会变化,我在Windows 2.6.5上尝试了@senderle 's spin on Vartec'的解决方案,但我遇到了错误,没有其他解决方案有效 . 我的错误是:
WindowsError: [Error 6] The handle is invalid
.我发现我必须将PIPE分配给每个句柄以使其返回我期望的输出 - 以下对我有效 .
并且这样调用,(
[0]
获取元组的第一个元素,stdout
):在了解更多之后,我相信我需要这些管道参数,因为我正在使用不同句柄的自定义系统,所以我必须直接控制所有std .
要停止控制台弹出窗口(使用Windows),请执行以下操作:
这个问题的答案取决于您使用的Python版本 . 最简单的方法是使用subprocess.check_output函数:
check_output
运行一个只接受参数作为输入的程序 . 它返回与打印完全相同的结果stdout
. 如果需要将输入写入stdin
,请跳至run
或Popen
部分 . 如果要执行复杂的shell命令,请参阅本答案末尾的shell=True
上的注释 .check_output
函数适用于几乎所有仍在广泛使用的Python版本(2.7).2但是对于更新版本,它不再是推荐的方法 .现代版本的Python(3.5或更高版本):运行
如果您使用 Python 3.5 或更高版本以及 do not need backwards compatibility ,则建议使用new run function . 它为
subprocess
模块提供了一个非常通用的高级API . 要捕获程序的输出,请将subprocess.PIPE
标志传递给stdout
关键字参数 . 然后访问返回的CompletedProcess对象的stdout
属性:返回值是一个
bytes
对象,所以如果你想要一个合适的字符串,你需要decode
它 . 假设被调用进程返回UTF-8编码的字符串:这可以全部压缩为单行:
如果要将输入传递给进程的
stdin
,请将bytes
对象传递给input
关键字参数:您可以通过传递
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开始提供 .它需要与
Popen
(见下文)相同的参数,并返回包含程序输出的字符串 . 这个答案的开头有一个更详细的用法示例 .您可以传递
stderr=subprocess.STDOUT
以确保返回的输出中包含错误消息 - 但不要将stderr=subprocess.PIPE
传递给check_output
. 它可能导致deadlocks . 如果不担心安全性,您还可以通过传递shell=True
来运行更复杂的shell命令,如下面的注释所述 .如果需要从
stderr
进行管道传输或将输入传递给进程,check_output
将无法完成任务 . 在这种情况下,请参阅下面的Popen
示例 .复杂的应用程序和Python的旧版本(2.6及以下版本):Popen
如果您需要深度向后兼容性,或者如果您需要比
check_output
提供的更复杂的功能,则必须直接使用Popen
对象,这些对象封装了子进程的低级API .Popen
构造函数接受不带参数的 a single command 或包含命令作为其第一项的 a list ,后跟任意数量的参数,每个参数作为列表中的单独项 . shlex.split可以帮助将字符串解析为格式正确的列表 . 对于进程IO管理和低级配置,Popen
对象也接受host of different arguments .要发送输入和捕获输出,
communicate
几乎总是首选方法 . 如:要么
如果设置
stdin=PIPE
,communicate
也允许您通过stdin
将数据传递给进程:注意Aaron Hall's answer,表示在某些系统上,您可能需要将
stdout
,stderr
和stdin
all设置为PIPE
(或DEVNULL
)让communicate
完全工作 .在极少数情况下,您可能需要复杂的实时输出捕获 . Vartec的回答表明了前进的方向,但如果不仔细使用,
communicate
以外的方法很容易出现死锁 .与上述所有函数一样,当不考虑安全性时,可以通过传递
shell=True
来运行更复杂的shell命令 .注意事项
1. Running shell commands: the shell=True argument
通常,每次调用
run
,check_output
或Popen
构造函数都会执行一个程序 . 这意味着没有花哨的bash式管道 . 如果要运行复杂的shell命令,可以传递shell=True
,这三个函数都支持 .但是,这样做会引发security concerns . 如果你做的不仅仅是轻量级脚本,你可能最好分别调用每个进程,并将每个进程的输出作为输入传递给下一个进程,通过
要么
直接连接管道的诱惑力很强;抵制它 . 否则,你可能会看到死锁或者必须做像this这样的hacky事情 .
2. Unicode considerations
check_output
在Python 2中返回一个字符串,但在Python 3中返回一个bytes
对象 . 如果你还没有,那么值得花点时间learn about unicode .这是一个 tricky 但是 super simple 解决方案,适用于许多情况:
使用命令的输出创建临时文件(此处为tmp),您可以从中读取所需的输出 .
注释中的额外注释:您可以在一次性作业的情况下删除tmp文件 . 如果您需要多次执行此操作,则无需删除tmp .
如果你需要在多个文件上运行shell命令,这对我来说就是一个诀窍 .
编辑:刚刚看到马克斯佩尔森的解决方案与J.F.塞巴斯蒂安的建议 . 走在前面,并将其纳入其中 .
这样更容易,但只适用于Unix(包括Cygwin) .
它返回一个带有(return_value,output)的元组
这仅适用于
python2.7
:它在python3
上不可用 . 对于兼容两者的解决方案,请使用subprocess
模块:现代Python解决方案(> = 3.1):
像这样的东西:
注意,我正在将stderr重定向到stdout,它可能不是你想要的,但我也想要错误消息 .
这个函数 yields line by line as they come (通常你必须等待子进程完成以获得整个输出) .
对于您的情况,用法将是:
我遇到了同样的问题但是想出了一个非常简单的方法
希望它有所帮助
注意:此解决方案是特定于python3的,因为
subprocess.getoutput()
在python2中不起作用I had a slightly different flavor of the same problem with the following requirements:
捕获并返回STDOUT消息,因为它们在STDOUT缓冲区中累积(即实时) .
@vartec通过使用生成器和'yield'来解决这个问题 .
以上关键字
打印所有STDOUT行(即使在完全读取STDOUT缓冲区之前进程退出)
不要浪费CPU周期以高频率轮询过程
检查子进程的返回码
如果我们得到非零错误返回码,则打印STDERR(与STDOUT分开) .
I've combined and tweaked previous answers to come up with the following:
This code would be executed the same as previous answers:
例如,执行('ls -ahl')区分三个/四个可能的返回和操作系统平台:
无输出,但运行成功
输出空行,运行成功
运行失败
输出一些东西,运行成功
功能如下