Как предотвратить печать разделяемой библиотеки C на stdout в python?

Я работаю с библиотекой python, которая импортирует разделяемую библиотеку C, которая печатает на stdout. Мне нужен чистый вывод, чтобы использовать его с каналами или перенаправлять в файлы. Печать выполняется вне 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)

Этот первый подход наполовину работает:
- По какой-то причине перед перемещением stdout требуется оператор "print", иначе всегда печатается приветственное слово. В результате вместо всего нечеткого файла, который обычно выводит библиотека, будет выведена пустая строка.
- Еще больше раздражает то, что он не работает при перенаправлении в файл:

$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)

Он печатает «привет», даже если я libc.fflush (stdout) сразу после printf. Я начинаю думать, что делать то, что я хочу, на python невозможно. Или, может быть, я неправильно получаю указатель файла на stdout.

Что вы думаете?

41
задан user48678 29 March 2017 в 09:42
поделиться