我想禁止运行可执行程序的函数产生的所有终端输出。
我试图通过使用上下文管理器来抑制Python函数的输出,该上下文管理器在每次调用函数时临时重新定义stdout和stderr。这样可以抑制print函数调用产生的终端输出,但是当函数调用产生终端输出的可执行文件时,它似乎不起作用。
print
那么,如何抑制Python函数调用的可执行文件的输出呢?
我的代码如下。我提供了一个示例函数,该函数调用ls以尝试说明我要抑制的终端输出的种类(尽管我要处理的函数是不同的)。
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提供的解决方案
#!/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()
我没有成功抑制来自print或的终端输出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.stderr为sys.stdout,并将文件描述符2替换为数字1:
stderr
stdout
sys.stderr
sys.stdout
2
1
@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)