当前位置: 首页 > 面试题库 >

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

邢杰
2023-03-14
问题内容

我想禁止运行可执行程序的函数产生的所有终端输出。

我试图通过使用上下文管理器来抑制Python函数的输出,该上下文管理器在每次调用函数时临时重新定义stdout和stderr。这样可以抑制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提供的解决方案

#!/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.stderrsys.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)


 类似资料:
  • 我已经能够使用pyInstaller从Python 3.4代码成功地生成Windows可执行文件。 但是,每次运行可执行文件(控制台应用程序)时,它都会在代码启动前输出以下内容: 我假设这是pyInstaller引导加载程序过程,如下所述。我想知道是否有一种方法可以抑制这个输出,而不抑制我自己的Python代码生成的输出? 附加信息: 生成单个可执行文件(使用选项) 运行在Windows 7 En

  • 问题内容: 我有一个名为’a’的二进制文件,它在被调用时生成输出。如果我从 在bashshell中,大部分输出被“a>/dev/null”抑制。所有的 输出被 我有一个名为“B”的python脚本,需要调用“a”。我希望能够 从“B”生成输出,同时禁止从“A”生成所有输出。 在“B”中,我试过, 以及,等等,但这些都不是 抑制A的所有输出。 我可以运行’B&>/dev/null’,但这也会抑制’B

  • 问题内容: 我是Unix环境的新手。 我想要一个小的聊天程序,将初始终端用于输入,并调用另一个终端进行输出。我一直在网上搜索,但没有任何运气。 好的,更具体地说,我正在C中的Mac上通过TCP / IP编写聊天程序。我想在两个不同的终端中分离输入和聊天消息输出。我可以找到有关如何在进程之间进行通信的资源,但是我不知道如何为输出调用另一个终端。 问题答案: 以您似乎正在做的方式生成另一个终端是非常不

  • 从Eclipse导出可运行的JAR文件是从另一台机器上的命令行启动Eclipse项目的最快方法。请参见此答案。 问题是,如果要从中运行的计算机上安装的JRE比Eclipse使用的JDK旧,则会出现以下错误: 我知道,在Eclipse上,我可以用较低的遵从性级别(例如,用1.6而不是1.7)构建项目,但这似乎不会影响导出的JAR文件。 关于如何导出要在旧JRE上执行的Runnable JAR文件的任

  • 好的,所以基本上,每次我看到这个问题被问到,它都没有我想要的答案,这就是为什么我要问自己。 基本上,我在BlueJ上做了一个java项目(遗憾的是,学校要求。但如果这是个问题,我可以将它导出到其他地方(最好是IntelliJ或Visual Studio代码)),但本质上,我想这样做,我只需双击我的.jar导出,它就会打开一个终端窗口并启动。然而,当我尝试这个方法时,我得到了这个错误:第一个错误 当

  • 终端中使用lldb运行可执行文件 进入lldb环境, 在终端内输入lldb回车 lldb 使用file命令, 将可执行文件包装成一个target (lldb) file test Current executable set to '/Users/shenyj/Documents/CodeForTest/staticOCLib/test' (x86_64). 运行可执行文件, 在刚刚的l