我想要编写一个函数来将执行 shell 命令并将其输出为 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'
2011-01-21 14:55:44
问题评论:

相关︰ stackoverflow.com/questions/2924310/...

回答:

为方便起见,提供 Python 2.7

subprocess.check_output(*popenargs, **kwargs)  

函数,采用 Popen 相同的参数,但会返回一个字符串,包含该程序的输出。您可以通过stderr=subprocess.STDOUT以确保该错误消息会包含在返回的输出-但没有通过将stderr=subprocess.PIPEcheck_output它会导致死锁如果您需要从stderr管道,请参阅下面的Popen示例。

如果您使用较旧的 python, Vartec 的方法会起作用。但更好的方法去-至少在简单情况下,无需实时输出捕获 — 是使用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=PIPEcommunicate还允许您通过stdin将数据传递给过程:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo
foofoo
')
>>> print out
foofoo

最后,请注意兆辉大厅的回答,这说明在某些系统上,您可能需要将stdoutstderrstdin设置所有为PIPE(或DEVNULL) 来获取communicate正常工作所。

是的我见过这一个,但我使用 2.6 (更不必说 python 版本我错)

同时与check_output()communicate() ,您必须等待,直到完成后, poll()与您将获得输出如说。实际上取决于您的需要。

此答案为我工作,其他人未。

如果这仅适用于更高版本的 Python,但可变out是的类型<class 'bytes'>我不确定。为了我不得不因此解码之前打印类似以字符串形式获取输出︰ out.decode("utf-8")

@Elena,您说的对,我不明确。我想不通过stderr=subprocess.PIPEcheck_output将其传递给Popen没什么关系。我编辑的答案;让我知道是否它看起来足够明确现在。

这种方法更容易,但仅适用于 Unix (包括 Cygwin)。

import commands
print commands.getstatusoutput('wc -l file')

它返回一个元组与 return_value (输出)

简单但有效

现在,否决但没有 subprocess.check_output 的旧 python 版本非常有用

请注意这是 Unix 特定。它将在 Windows 上,例如失败。

+ 1 得远古版本 python 2.4 英寸,这是非常有帮助

比其他人更容易一些。在这里,没有人使用 3.x 否决

类似的︰

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,

感谢您的帮助 !但函数进入我的无限循环...

要确保实现某种活动的循环来获得要避免潜在的死锁waitcall函数中的输出。

@Silver 光︰ 您的流程可能正在等待来自用户的输入。请尝试为stdin和文件只要Popen返回的结束提供一个PIPE值。

@Andre: 是的,实际上在我生产代码中使用线程。Timer() 执行 p.terminate() 时超时。

@fuenfundachtzig︰ 直到读取所有输出,并因此大不适合在内存中的输出将不会返回.readlines()也要避免缺少缓冲的数据后有退出的子进程应的模拟if retcode is not None: yield from p.stdout.readlines(); break

Vartec 的答案不会读取所有行,这样做没有一个版本︰

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

用法是相同的接受的答案︰

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)

您可以使用return iter(p.stdout.readline, b'')而不是 while 循环

它是很棒的 iter 的不知道的 !我更新了代码。

我很肯定所有标准输出保持输出,它是使用一个缓冲区的流对象。我使用了非常类似的方法会占用所有剩余 Popen 已经完成,并在我种情况下,使用 poll() 和 readline 执行期间捕获输出实时还后输出。

我删除了我有误导性的评论。我可以确认, p.stdout.readline()可能会返回非空以前缓冲输出即使子进程已退出 (p.poll()不是None).

此代码不起作用。在这里看到stackoverflow.com/questions/24340877/...

您实际效果可能有所不同,我尝试 @senderle 的数值调节钮 Vartec 的解决方案在 Python 2.6.5,在 Windows 上,但时遇到错误,以及没有其他解决方案进行工作。我的错误是︰ WindowsError: [Error 6] The handle is invalid.

我发现,我不得不将管道分配给每个句柄以使其返回预期的输出以下有效的回答。

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

并调用如下,([0]获取第一个元素的元组,stdout):

run_command('tracert 11.1.0.1')[0]

了解更多之后,我认为我需要这些管道参数,因为我正在研究使用不同手柄,因此我不得不直接控制 std 的所有自定义系统

若要停止控制台 (与 Windows) 的弹出窗口,请执行此操作︰

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

令人感兴趣,这必须是 Windows 的事情。我将添加了指向此在的情况下,用户会发现类似的错误。

使用DEVNULL改为subprocess.PIPE如果您没有读/写从管道否则为可能会挂起子进程。

听起来很好的提示,@J.F.Sebastian

请输入您的翻译

Running shell command from Python and capturing the output

确认取消