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

时间:2018-03-07 09:03:07

标签: python subprocess mbrola

我正在使用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

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

根本问题是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和tderr。这就是为什么即使你将espeak的stderr传递给/ dev / null,以及你自己的程序也是如此。

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

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

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

而且,你真的应该首先检查一个新版本,如果他们尚未修复它,请向上游报告此错误。