子进程,stderr 到 DEVNULL 但打印错误

Subprocess, stderr to DEVNULL but errors are printed

我正在使用 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 错误。我想我无法修复它。但它有效,所以我只想消除错误。我能怎么做 ?有办法吗?


编辑,回应

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

运行它跟setsid (just add that string in front of the command and arguments). That will stop it from opening /dev/tty to report the malloc errors. It will also prevent terminal signals一样,包括SIGHUP当终端关闭时,不影响进程,这可能是好事也可能是坏事。

或者,将环境变量 LIBC_FATAL_STDERR_ 设置为 some nonempty string, with whose name I was able to find questions

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

这些警告由 glibc 的 malloc 检查器发出,在 mallopt 文档中有描述。如果启用堆检查,每个检测到的 malloc(以及 free 和相关函数)的错误都将被打印到 stderr,但如果它被禁用,则什么也不会做。 (也可以使用其他可能性,但这与此处无关。)

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

此外,文档暗示除非 malloc_printerr 被替换,否则 malloc 错误会转到 stderr。但同样,许多发行版确实用一个故意更难忽略的函数替换它,如果假装则记录到当前进程的 tty,否则记录到 stderr。这就是为什么即使您将 espeak 的 stderr 和您自己的程序通过管道传输到 /dev/null 也会显示的原因。

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

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

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

更短

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