【问题标题】:How to hide output of subprocess如何隐藏子进程的输出
【发布时间】:2012-07-01 10:40:40
【问题描述】:

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

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

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

不幸的是,没有记录的选项可以关闭它的冗长,所以我正在寻找一种方法来仅在视觉上使其静音并保持打开的外壳清洁以进行进一步的交互。

我该怎么做?

【问题讨论】:

  • 那你不能直接用 os.system 打电话吗?不理想,但我认为不应该打印
  • @JoranBeasley: os.system() 将打印到控制台,除非您重定向 shell 命令
  • 不,os.system('espeak '+ text) 重现了这种行为。
  • @ferkulat:我更新了我的答案以显示os.system 语法。虽然只是为了说明。坚持使用子流程
  • 非 2.7 特定版本:stackoverflow.com/questions/5495078/… 允许完美的subprocess.DEVNUL 解决方案。

标签: python subprocess espeak


【解决方案1】:

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

import os
import subprocess

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

对于python

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

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

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

【讨论】:

  • 微型精选:如果subprocess.DEVNULL 不可用(os.devnull,如果您不检查其返回的代码,请使用check_call() 而不是call(),打开stdin/stdout/stderr 的二进制模式文件,不鼓励使用 os.system()&> 在 Ubuntu 上不适用于 sh,可以使用显式的 >/dev/null 2>&1
  • @J.F.Sebastian:感谢您的建议。我实际上是想使用os.devnull,但不小心输入了它。另外,我坚持使用call 的OP,因为他们没有发现check_call 可能引发的异常。对于os.system 重定向,它更多地只是说明了子流程方法的有效使用正在做什么。不是第二个建议。
  • 你打开的FNULL不需要关闭吗?
  • 注意一下,可以在subprocess.call中使用close_fds=True在子进程存在后关闭FNULL描述符
  • @ewino: 在close_fds=True 上,文件描述符在之后 fork()之前 execvp() 即关闭,即它们在child 进程只是在 可执行文件运行之前。 close_fds=True won't work on Windows if any of the streams are redirectedclose_fds 不会关闭 parent 进程中的文件。
【解决方案2】:

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

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

【讨论】:

  • 请注意,这会产生一个不完全通用的DEVNULL,就像subprocess 提供的那样;由于已打开wb,因此不能用于stdin
  • @Reid:如果需要,可以使用'r+b' 模式。
  • @jfs 8 年后我们只做stdout=subprocess.DEVNULL,对吧?
  • 代码兼容 Python 2/3。如果您不需要 Python 2,那么导入:from subprocess import DEVNULL 就足够了。
【解决方案3】:

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

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

您还可以使用以下命令抑制标准错误:

    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

在这里,您可以使用

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

【讨论】:

  • 更准确地说,它返回标准输出。除了能够忽略它之外,这也很棒。
  • 我认为这更直接。 @StudentT 我认为您应该使用 CalledProcessError 处理错误。 except subprocess.CalledProcessError as e 然后使用e.codee.output
【解决方案4】:

从 Python3 开始,您不再需要打开 devnull 并且可以调用 subprocess.DEVNULL

您的代码将按如下方式更新:

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

【讨论】:

  • 有效!此外,可以在上面的代码中将stderrstdout 交换(或作为另一个参数附加)以抑制输出。 “输出”在问题的标题中,是什么让我来到这里......也许微不足道,但认为值得一提。
【解决方案5】:

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

import commands

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

【讨论】:

  • a) 它不会丢弃输入,它会在内存中不必要地累积它 b) 如果text 中有引号,或者使用不同的字符编码,或者对于命令行来说太大,它会中断c) 仅适用于 Unix(在 Python 2 上)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多