Мы можем использовать os.dup2()
и os.pipe()
, чтобы заменить весь дескриптор файла стандартного вывода (fd 1) на канал, который мы можем прочитать сами. Вы можете сделать то же самое с stderr (fd 2).
В этом примере используется select.select()
, чтобы проверить, есть ли в канале (нашем поддельном stdout) данные, ожидающие записи, поэтому мы можем безопасно их распечатать, не блокируя выполнение нашего скрипта.
Поскольку мы полностью заменяем дескриптор файла stdout для этого процесса и любых подпроцессов, этот пример может даже захватывать выходные данные дочерних процессов.
import os, sys, select
# the pipe would fail for some reason if I didn't write to stdout at some point
# so I write a space, then backspace (will show as empty in a normal terminal)
sys.stdout.write(' \b')
pipe_out, pipe_in = os.pipe()
# save a copy of stdout
stdout = os.dup(1)
# replace stdout with our write pipe
os.dup2(pipe_in, 1)
# check if we have more to read from the pipe
def more_data():
r, _, _ = select.select([pipe_out], [], [], 0)
return bool(r)
# read the whole pipe
def read_pipe():
out = ''
while more_data():
out += os.read(pipe_out, 1024)
return out
# testing print methods
import ctypes
libc = ctypes.CDLL('libc.so.6')
print 'This text gets captured by myStdOut'
libc.printf('This text fails to be captured by myStdOut\n')
# put stdout back in place
os.dup2(stdout, 1)
print 'Contents of our stdout pipe:'
print read_pipe()