编程语言
首页 > 编程语言> > 如何通过Python函数运行的可执行文件的终端输出以一般方式静音?

如何通过Python函数运行的可执行文件的终端输出以一般方式静音?

作者:互联网

我想抑制运行可执行文件的函数产生的所有终端输出.

我试图通过使用每次调用函数时临时重新定义stdout和stderr的上下文管理器来抑制Python函数的输出.这会抑制函数中的print调用产生的终端输出,但是当函数调用产生终端输出的可执行文件时,它似乎不起作用.

那么,如何抑制Python函数调用的可执行文件的输出?

我的代码如下.我已经包含了一个示例函数,它调用ls来试图说明我想要抑制的终端输出的类型(虽然我正在处理的函数是不同的).

#!/usr/bin/env python

import os
import subprocess
import sys

def main():

    print("hello")

    with silence():
        print("there")

    print("world")

    with silence():
        engage_command(command = "ls")

class silence(object):

    def __init__(
        self,
        stdout = None,
        stderr = None
        ):
        if stdout == None and stderr == None:
            devnull = open(os.devnull, "w")
            stdout = devnull
            stderr = devnull
        self._stdout = stdout or sys.stdout
        self._stderr = stderr or sys.stderr

    def __enter__(
        self
        ):
        self.old_stdout = sys.stdout
        self.old_stderr = sys.stderr
        self.old_stdout.flush()
        self.old_stderr.flush()
        sys.stdout = self._stdout
        sys.stderr = self._stderr

    def __exit__(
        self,
        exc_type,
        exc_value,
        traceback
        ):
        self._stdout.flush()
        self._stderr.flush()
        sys.stdout = self.old_stdout
        sys.stderr = self.old_stderr

def engage_command(
    command = None
    ):
    process = subprocess.Popen(
        [command],
        shell      = True,
        executable = "/bin/bash")
    process.wait()
    output, errors = process.communicate()
    return output

if __name__ == "__main__":
    main()

在我的特定情况下,我正在尝试运行以下函数(而不是上面的ls函数):

with propyte.silence():
    stream = pyaudio.PyAudio().open(
        format   = pyaudio.PyAudio().get_format_from_width(1),
        channels = 1, 
        rate     = bitrate, 
        output   = True
    )

运行时,会产生如下输出:

ALSA lib pcm_dsnoop.c:606:(snd_pcm_dsnoop_open) unable to open slave
ALSA lib pcm_dmix.c:1029:(snd_pcm_dmix_open) unable to open slave
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm_dmix.c:1029:(snd_pcm_dmix_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for 4294967295, skipping unlock

我想压制那个输出.

编辑:测试@Matthias提供的a solution

#!/usr/bin/env python

import contextlib
import os
import subprocess
import sys

def main():

    print("hello")

    with silence():
        print("there")

    print("world")

    with silence():
        engage_command(command = "ls")

@contextlib.contextmanager
def silence():
    devnull = os.open(os.devnull, os.O_WRONLY)
    old_stderr = os.dup(2)
    sys.stderr.flush()
    os.dup2(devnull, 2)
    os.close(devnull)
    try:
        yield
    finally:
        os.dup2(old_stderr, 2)
        os.close(old_stderr)

def engage_command(
    command = None
    ):
    process = subprocess.Popen(
        [command],
        shell      = True,
        executable = "/bin/bash")
    process.wait()
    output, errors = process.communicate()
    return output

if __name__ == "__main__":
    main()

我没有成功地抑制打印或ls的终端输出,我不知道为什么.

解决方法:

您可以从PyAudio切换到sounddevice模块,该模块已经负责消除终端输出(参见#12).这是在那里完成的(使用CFFI):

from cffi import FFI
import os

ffi = FFI()
ffi.cdef("""
/* from stdio.h */
FILE* fopen(const char* path, const char* mode);
int fclose(FILE* fp);
FILE* stderr;  /* GNU C library */
FILE* __stderrp;  /* Mac OS X */
""")
try:
    stdio = ffi.dlopen(None)
    devnull = stdio.fopen(os.devnull.encode(), b'w')
except OSError:
    return
try:
    stdio.stderr = devnull
except KeyError:
    try:
        stdio.__stderrp = devnull
    except KeyError:
        stdio.fclose(devnull)

如果您需要纯Python解决方案,可以尝试使用此上下文管理器:

import contextlib
import os
import sys

@contextlib.contextmanager
def ignore_stderr():
    devnull = os.open(os.devnull, os.O_WRONLY)
    old_stderr = os.dup(2)
    sys.stderr.flush()
    os.dup2(devnull, 2)
    os.close(devnull)
    try:
        yield
    finally:
        os.dup2(old_stderr, 2)
        os.close(old_stderr)

这是一篇关于该主题的非常有用的博文:http://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/.

更新:

上面的上下文管理器使标准错误输出(stderr)静音,该输出用于原始问题中提到的来自PortAudio的恼人消息.要删除标准输出(stdout),就像在更新的问题中一样,你必须用sys.stdout替换sys.stderr,用数字1替换文件描述符2:

@contextlib.contextmanager
def ignore_stdout():
    devnull = os.open(os.devnull, os.O_WRONLY)
    old_stdout = os.dup(1)
    sys.stdout.flush()
    os.dup2(devnull, 1)
    os.close(devnull)
    try:
        yield
    finally:
        os.dup2(old_stdout, 1)
        os.close(old_stdout)

标签:python,console,silent,executable,pyaudio
来源: https://codeday.me/bug/20190923/1814318.html