【问题标题】:Subprocess, stderr to DEVNULL but errors are printed子进程,stderr 到 DEVNULL 但打印错误
【发布时间】:2018-03-07 09:03:07
【问题描述】:

我正在使用 python 开发一个法语聊天机器人。对于第一次文本到语音的尝试,我使用 espeak 和 mbrola。我用子流程来称呼它:

from subprocess import run, DEVNULL

def speak(text):
    command = ["espeak", "-vmb-fr1", text]
    run(command, stderr=DEVNULL, stdout=DEVNULL)

speak("Bonjour.")

如你所见,我将 stderr 和 stdout 发送到 /dev/null

当我运行程序时,它似乎工作,espeak 正在说话,但我明白了:

*** Error in `mbrola': free(): invalid pointer: 0x08e3af18 ***
*** Error in `mbrola': free(): invalid pointer: 0x0988af88 ***

我认为这是 mbrola 中的 C 错误。我想我无法修复它。但它有效,所以我只想忽略错误。我能怎么做 ?有什么办法吗?


编辑,回复abarnert

当我通过 shell (python myscript.py 2>&1 >/dev/null) 重定向 stdout 和 stderr 时,消息仍然显示。

  • 发行版:Debian 9.3
  • glibc 版本:2.24

【问题讨论】:

  • 我相信这些消息是由您的系统 malloc 库发出的,而不是由实际的 espeakmbrola 代码发出的,因为它在 mbrola 中检测到一个危险的错误。也许它会将消息发送到您的控制台,而不是发送到父母可以捕获的任何内容?尝试使用自己的 stdout 和由 shell 重定向的 stderr 运行脚本,看看消息是否仍然显示。
  • 感谢您的评论。请你能告诉你“用自己的标准输出和由shell重定向的标准错误运行你的脚本”是什么意思吗?对不起,如果这是一个愚蠢的问题。
  • python myscript.py 2>&1 >/dev/null
  • 它仍然显示...
  • 首先,set |grep MALLOC_CHECK_ 向您展示了什么?接下来,如果您export MALLOC_CHECK_=0 并再次尝试您的代码会发生什么? (请注意名称末尾的时髦下划线。这很重要。)同时,您是否检查过 espeak/mbrola 的较新版本,或者向它们提交了错误?

标签: python subprocess mbrola


【解决方案1】:

使用setsid 运行它(只需在命令和参数前面添加该字符串)。这将阻止它打开 /dev/tty 来报告 malloc 错误。还会防止terminal signals,包括终端关闭时的SIGHUP,影响进程,这可能是好事,也可能是坏事。

或者,将环境变量LIBC_FATAL_STDERR_ 设置为some nonempty string,我可以找到其名称several similar questions

【讨论】:

  • 谢谢!我认为使用 setsid 运行 espeak 是最简单的解决方案。我会用的。
【解决方案2】:

根本问题是mbrola/espeak有一个严重的内存分配错误。如果您还没有检查新版本并将错误报告给他们,那是您应该做的第一件事。

这些警告由 glibc 的 malloc 检查器发出,在 mallopt 文档中进行了描述。如果启用堆检查,malloc(以及free 和相关函数)检测到的每个错误都将打印到 stderr,但如果它被禁用,则不会执行任何操作。 (也有其他可能性,但这里不相关。)

根据文档,除非程序显式调用 mallopt,否则将环境变量 MALLOC_CHECK_ 设置为 0 或根本不设置它应该意味着没有 malloc 调试输出。但是,大多数主要发行版(从 Debian 开始)早就发布了 glibc,它被配置为默认值 1(意味着打印错误消息)而不是 0。您仍然可以通过显式设置 MALLOC_CHECK_=0 来覆盖它。

此外,文档暗示 malloc 错误会转到 stderr,除非 malloc_printerr 被替换。但是同样,许多发行版确实将其替换为故意难以忽略的功能,如果假装则记录到当前进程的 tty,如果不是则记录到 stderr。这就是为什么即使您将espeak 的标准错误传送到/dev/null 以及您自己的程序也会显示的原因。

因此,要隐藏这些错误,您可以:

  • espeak 中的环境变量MALLOC_CHECK_ 设置为0,这将禁用检查。
  • 防止espeak打开tty,这意味着检查仍然会进行,但输出将无处可去。

使用setsid,一种在新进程开始时调用setsid 的工具,是完成后者的一种方法。这是否是一个好主意取决于您是否希望流程领导自己的流程组。你真的应该阅读这意味着什么并决定你想要什么,而不是在选项之间进行选择,因为输入 setsid 比输入 MALLOC_CHECK_=0 短。

同样,你真的应该先检查新版本,如果他们还没有修复这个错误,请向上游报告。

【讨论】:

    猜你喜欢
    • 2017-02-10
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 2011-06-18
    • 2011-08-10
    • 2015-12-12
    • 1970-01-01
    • 2021-01-20
    相关资源
    最近更新 更多