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

如何防止C共享库在python中的stdout上打印?

山阳辉
2023-03-14
问题内容

我使用的是python库,该库导入了在stdout上打印的C共享库。我想要一个干净的输出以便与管道一起使用或在文件中重定向。打印是在python之外的共享库中完成的。

一开始,我的方法是:

# file: test.py
import os
from ctypes import *
from tempfile import mktemp

libc = CDLL("libc.so.6")

print # That's here on purpose, otherwise hello word is always printed

tempfile = open(mktemp(),'w')
savestdout = os.dup(1)
os.close(1)
if os.dup(tempfile.fileno()) != 1:
    assert False, "couldn't redirect stdout - dup() error"

# let's pretend this is a call to my library
libc.printf("hello world\n")

os.close(1)
os.dup(savestdout)
os.close(savestdout)

第一种方法是行之有效的:
-出于某种原因,它在移动标准输出之前需要一个“打印”语句,否则总是打印问候词。结果,它将打印一个空行,而不是库通常输出的所有模糊测试。
-更烦人的是,重定向到文件时失败:

$python test.py > foo && cat foo

hello world

我的第二次python尝试是从注释中给出的另一个类似线程中获得启发的:

import os
import sys
from ctypes import *
libc = CDLL("libc.so.6")

devnull = open('/dev/null', 'w')
oldstdout = os.dup(sys.stdout.fileno())
os.dup2(devnull.fileno(), 1)

# We still pretend this is a call to my library
libc.printf("hello\n")

os.dup2(oldstdout, 1)

这也无法防止打印“ hello”。

因为我觉得这有点低,所以我决定完全使用ctypes。我从此C程序中获得了灵感,该程序不显示任何内容:

#include <stdio.h>

int main(int argc, const char *argv[]) {
    char buf[20];
    int saved_stdout = dup(1);
    freopen("/dev/null", "w", stdout);

    printf("hello\n"); // not printed

    sprintf(buf, "/dev/fd/%d", saved_stdout);
    freopen(buf, "w", stdout);

    return 0;
}

我建立了以下示例

from ctypes import *
libc = CDLL("libc.so.6")

saved_stdout = libc.dup(1)
stdout = libc.fdopen(1, "w")
libc.freopen("/dev/null", "w", stdout);

libc.printf("hello\n")

libc.freopen("/dev/fd/" + str(saved_stdout), "w", stdout)

即使我在printf之后是libc.fflush(stdout),也会打印“
hello”。我开始认为可能无法在python中做我想做的事情。也许我获取指向stdout的文件指针的方法不正确。

你怎么看?


问题答案:

基于@Yinon
Ehrlich的答案
。此变体尝试避免泄漏文件描述符:

import os
import sys
from contextlib import contextmanager

@contextmanager
def stdout_redirected(to=os.devnull):
    '''
    import os

    with stdout_redirected(to=filename):
        print("from Python")
        os.system("echo non-Python applications are also supported")
    '''
    fd = sys.stdout.fileno()

    ##### assert that Python and C stdio write using the same file descriptor
    ####assert libc.fileno(ctypes.c_void_p.in_dll(libc, "stdout")) == fd == 1

    def _redirect_stdout(to):
        sys.stdout.close() # + implicit flush()
        os.dup2(to.fileno(), fd) # fd writes to 'to' file
        sys.stdout = os.fdopen(fd, 'w') # Python writes to fd

    with os.fdopen(os.dup(fd), 'w') as old_stdout:
        with open(to, 'w') as file:
            _redirect_stdout(to=file)
        try:
            yield # allow code to be run with the redirected stdout
        finally:
            _redirect_stdout(to=old_stdout) # restore stdout.
                                            # buffering and flags such as
                                            # CLOEXEC may be different


 类似资料:
  • 问题内容: 这是使用g ++ 进行动态共享库编译的后续版本。 我正在尝试在Linux上的C++中创建一个共享的类库。当我尝试使用库中定义的类时,我的问题开始了。我链接到的第二篇教程展示了如何加载用于创建库中定义的类的对象的符号,但是没有_使用_ 这些对象来完成任何工作。 有谁知道用于创建共享C ++类库的更完整的教程,该教程还显示了如何在单独的可执行文件中 使用 这些类?一个非常简单的教程,显示了

  • 问题内容: 我正在Linux下使用C ++开发共享库,并且我希望该库使用log4cxx进行日志记录。但是,我不确定该如何设置。为了使log4cxx正常工作,我需要创建一个记录器对象。我如何确保在加载库时创建了该对象? 我怀疑将记录器对象创建为全局变量,然后从我的库的任何源文件中使用它,在标头中将其声明为extern,将是最容易的。但是,一旦应用程序连接到库,如何自动创建记录器? 我知道在Windo

  • 问题内容: 我有一个程序,在运行过程中有时需要调用python才能执行某些任务。我需要一个调用python并 捕获pythons stdout 并将其放入某个文件的函数。这是函数的声明 我的问题是捕获 给定命令 (pythonInput)的 所有python输出 。我没有使用python API的经验,我不知道执行此操作的正确方法是什么。我尝试过的第一件事是使用Py_run_SimpleStrin

  • 问题内容: 我正在从python脚本中调用一个so文件。据我了解,我真的不需要释放使用ctypes在python中打开的共享库。但是,在我的so文件代码中,它dlopen另一个so文件并且不执行dlclose()。在这种情况下,从python端使用安全吗?我不必释放在ctypes内部加载的共享库soe文件吗? 问题答案: 始终遵循 “自己清洁后清理 ”的规则(尽管现代技术会为您提供清洁方面的帮助)

  • 问题内容: 由于某些其他原因,我使用的c ++共享库将一些文本输出到标准输出。在python中,我想捕获输出并 保存到一个变量中 。关于重定向标准输出,还有许多类似的问题,但在我的代码中不起作用。 在第5行中, func() 将调用共享库,共享库生成的文本仍输出到控制台!如果将 func() 更改 为print“ hello” ,则可以使用! 我的问题是: 如何将c ++共享库的stdout捕获

  • 问题内容: 我有一个Python脚本正在使用我的雇主提供的某些封闭式Python函数(即我无法编辑这些函数)。当我调用这些函数时,它们会将输出打印到我想抑制的Linux终端上。我试过通过重定向标准输出/标准错误; 但这无法捕获输出。我认为我通过Python调用的函数(上面的rogue_function())实际上是经过编译的C代码的包装程序,它们实际上是在进行打印。 有谁知道一种方法可以对某个函数