Я работаю с библиотекой python, которая импортирует совместно используемую библиотеку C, которая печатает на stdout. Я хочу чистый вывод, чтобы использовать его с каналами или перенаправлять файлы. Отпечатки выполняются за пределами python в общей библиотеке.
В начале мой подход:
# file: test.py
import os
from ctypes import *
from tempfile import mktemp
libc = CDLL("libc.so.6")
print # That 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 pretend this is a call to my library
libc.printf("hello world\n")
os.close(1)
os.dup(savestdout)
os.close(savestdout)
Этот первый подход работает наполовину:
- По какой-то причине ему нужно выполнить "печать" непосредственно перед перемещением stdout, иначе приветственное слово всегда печатается. В результате он будет печатать пустую строку, а не весь fuzz, который обычно выводит библиотека.
- Больше раздражает, он не работает при перенаправлении в файл:
$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)
Это также не позволяет предотвратить "привет" от печати.
Поскольку я чувствовал, что это был немного низкий уровень, я тогда решил полностью перейти к 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, не прав.
Как вы думаете?