如何隐藏子进程的输出

我在Ubuntu上使用eSpeak,并有一个Python 2.7脚本,打印并说出一条消息:

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

eSpeak产生所需的声音,但混乱的外壳与一些错误(ALSA lib…例如,没有插座连接),所以我不容易阅读之前打印的内容。退出码为0。

不幸的是,没有文档记录的选项来关闭它的冗长性,所以我正在寻找一种方法,只在视觉上关闭它,并保持打开的shell干净,以便进行进一步的交互。

我该怎么做呢?

300055 次浏览

对于python >= 3.3,将输出重定向到DEVNULL:

import os
import subprocess


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

对于python <3.3,包括2.7使用:

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

它实际上与运行这个shell命令是一样的:

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

下面是一个更便于携带的版本(只是为了好玩,对你的情况来说不是必须的):

#!/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

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

import commands


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

使用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)

从Python3开始,你不再需要打开devnull,可以调用子流程。DEVNULL

你的代码会像这样更新:

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