如何在Python 2.7中隐藏子进程的输出

问题:如何在Python 2.7中隐藏子进程的输出

我在Ubuntu上使用eSpeak,并且有一个Python 2.7脚本可以打印和显示一条消息:

import subprocess
text = 'Hello World.'
print text
subprocess.call(['espeak', text])

eSpeak产生所需的声音,但由于一些错误(ALSA lib …,没有套接字连接)而使外壳混乱,因此我无法轻松读取之前打印的内容。退出代码为0。

不幸的是,没有记录的选项可以关闭其详细信息,因此我正在寻找一种方法,仅在视觉上使其静音并保持打开的外壳干净以进行进一步的交互。

我怎样才能做到这一点?

I’m using eSpeak on Ubuntu and have a Python 2.7 script that prints and speaks a message:

import subprocess
text = 'Hello World.'
print text
subprocess.call(['espeak', text])

eSpeak produces the desired sounds, but clutters the shell with some errors (ALSA lib…, no socket connect) so i cannot easily read what was printed earlier. Exit code is 0.

Unfortunately there is no documented option to turn off its verbosity, so I’m looking for a way to only visually silence it and keep the open shell clean for further interaction.

How can I do this?


回答 0

将输出重定向到DEVNULL:

import os
import subprocess

FNULL = open(os.devnull, 'w')
retcode = subprocess.call(['echo', 'foo'], stdout=FNULL, stderr=subprocess.STDOUT)

它实际上与运行此shell命令相同:

retcode = os.system("echo 'foo' &> /dev/null")

Redirect the output to DEVNULL:

import os
import subprocess

FNULL = open(os.devnull, 'w')
retcode = subprocess.call(['echo', 'foo'], 
    stdout=FNULL, 
    stderr=subprocess.STDOUT)

It is effectively the same as running this shell command:

retcode = os.system("echo 'foo' &> /dev/null")

Update: This answer applies to the original question relating to python 2.7. As of python >= 3.3 an official subprocess.DEVNULL symbol was added.

retcode = subprocess.call(['echo', 'foo'], 
    stdout=subprocess.DEVNULL, 
    stderr=subprocess.STDOUT)

回答 1

这是一个更便携的版本(只是为了好玩,在您的情况下没有必要):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from subprocess import Popen, PIPE, STDOUT

try:
    from subprocess import DEVNULL # py3k
except ImportError:
    import os
    DEVNULL = open(os.devnull, 'wb')

text = u"René Descartes"
p = Popen(['espeak', '-b', '1'], stdin=PIPE, stdout=DEVNULL, stderr=STDOUT)
p.communicate(text.encode('utf-8'))
assert p.returncode == 0 # use appropriate for your program error handling here

Here’s a more portable version (just for fun, it is not necessary in your case):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from subprocess import Popen, PIPE, STDOUT

try:
    from subprocess import DEVNULL # py3k
except ImportError:
    import os
    DEVNULL = open(os.devnull, 'wb')

text = u"René Descartes"
p = Popen(['espeak', '-b', '1'], stdin=PIPE, stdout=DEVNULL, stderr=STDOUT)
p.communicate(text.encode('utf-8'))
assert p.returncode == 0 # use appropriate for your program error handling here

回答 2

使用subprocess.check_output(python 2.7中的新功能)。如果命令失败,它将抑制stdout并引发异常。(它实际上返回stdout的内容,因此您可以在以后的程序中使用它。)例如:

import subprocess
try:
    subprocess.check_output(['espeak', text])
except subprocess.CalledProcessError:
    # Do something

您还可以使用以下命令抑制stderr:

    subprocess.check_output(["espeak", text], stderr=subprocess.STDOUT)

对于2.7之前的版本,请使用

import os
import subprocess
with open(os.devnull, 'w')  as FNULL:
    try:
        subprocess._check_call(['espeak', text], stdout=FNULL)
    except subprocess.CalledProcessError:
        # Do something

在这里,您可以使用

        subprocess._check_call(['espeak', text], stdout=FNULL, stderr=FNULL)

Use subprocess.check_output (new in python 2.7). It will suppress stdout and raise an exception if the command fails. (It actually returns the contents of stdout, so you can use that later in your program if you want.) Example:

import subprocess
try:
    subprocess.check_output(['espeak', text])
except subprocess.CalledProcessError:
    # Do something

You can also suppress stderr with:

    subprocess.check_output(["espeak", text], stderr=subprocess.STDOUT)

For earlier than 2.7, use

import os
import subprocess
with open(os.devnull, 'w')  as FNULL:
    try:
        subprocess._check_call(['espeak', text], stdout=FNULL)
    except subprocess.CalledProcessError:
        # Do something

Here, you can suppress stderr with

        subprocess._check_call(['espeak', text], stdout=FNULL, stderr=FNULL)

回答 3

由于Python3你不再需要打开devnull并且可以调用subprocess.DEVNULL

您的代码将这样更新:

import subprocess
text = 'Hello World.'
print(text)
subprocess.call(['espeak', text], stderr=subprocess.DEVNULL)

As of Python3 you no longer need to open devnull and can call subprocess.DEVNULL.

Your code would be updated as such:

import subprocess
text = 'Hello World.'
print(text)
subprocess.call(['espeak', text], stderr=subprocess.DEVNULL)

回答 4

为什么不使用commands.getoutput()代替呢?

import commands

text = "Mario Balotelli" 
output = 'espeak "%s"' % text
print text
a = commands.getoutput(output)

Why not use commands.getoutput() instead?

import commands

text = "Mario Balotelli" 
output = 'espeak "%s"' % text
print text
a = commands.getoutput(output)