Hay una contextlib.redirect_stdout()función en Python 3.4:
from contextlib import redirect_stdout
with open('help.txt', 'w') as f:
with redirect_stdout(f):
print('it now prints to `help.text`')
Esto es similar a:
import sys
from contextlib import contextmanager
@contextmanager
def redirect_stdout(new_target):
old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
try:
yield new_target # run some code with the replaced stdout
finally:
sys.stdout = old_target # restore to the previous value
que se puede usar en versiones anteriores de Python. La última versión no es reutilizable . Se puede hacer uno si se desea.
No redirige el stdout en el nivel de descriptores de archivo, por ejemplo:
import os
from contextlib import redirect_stdout
stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, redirect_stdout(f):
print('redirected to a file')
os.write(stdout_fd, b'not redirected')
os.system('echo this also is not redirected')
b'not redirected'y 'echo this also is not redirected'no se redirigen al output.txtarchivo.
Para redirigir en el nivel de descriptor de archivo, os.dup2()podría usarse:
import os
import sys
from contextlib import contextmanager
def fileno(file_or_fd):
fd = getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
if not isinstance(fd, int):
raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
return fd
@contextmanager
def stdout_redirected(to=os.devnull, stdout=None):
if stdout is None:
stdout = sys.stdout
stdout_fd = fileno(stdout)
# copy stdout_fd before it is overwritten
#NOTE: `copied` is inheritable on Windows when duplicating a standard stream
with os.fdopen(os.dup(stdout_fd), 'wb') as copied:
stdout.flush() # flush library buffers that dup2 knows nothing about
try:
os.dup2(fileno(to), stdout_fd) # $ exec >&to
except ValueError: # filename
with open(to, 'wb') as to_file:
os.dup2(to_file.fileno(), stdout_fd) # $ exec > to
try:
yield stdout # allow code to be run with the redirected stdout
finally:
# restore stdout to its previous value
#NOTE: dup2 makes stdout_fd inheritable unconditionally
stdout.flush()
os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied
El mismo ejemplo funciona ahora si stdout_redirected()se usa en lugar de redirect_stdout():
import os
import sys
stdout_fd = sys.stdout.fileno()
with open('output.txt', 'w') as f, stdout_redirected(f):
print('redirected to a file')
os.write(stdout_fd, b'it is redirected now\n')
os.system('echo this is also redirected')
print('this is goes back to stdout')
El resultado que antes se imprimía en stdout ahora se mantiene output.txtmientras el stdout_redirected()administrador de contexto esté activo.
Nota: stdout.flush()no vacía las memorias intermedias de C stdio en Python 3 donde la E / S se implementa directamente en las llamadas read()/ write()system. Para vaciar todas las secuencias de salida de C stdio abiertas, puede llamar libc.fflush(None)explícitamente si alguna extensión de C usa E / S basadas en stdio:
try:
import ctypes
from ctypes.util import find_library
except ImportError:
libc = None
else:
try:
libc = ctypes.cdll.msvcrt # Windows
except OSError:
libc = ctypes.cdll.LoadLibrary(find_library('c'))
def flush(stream):
try:
libc.fflush(None)
stream.flush()
except (AttributeError, ValueError, IOError):
pass # unsupported
Puede usar el stdoutparámetro para redirigir otras secuencias, no solo sys.stdout, por ejemplo, para fusionar sys.stderry sys.stdout:
def merged_stderr_stdout(): # $ exec 2>&1
return stdout_redirected(to=sys.stdout, stdout=sys.stderr)
Ejemplo:
from __future__ import print_function
import sys
with merged_stderr_stdout():
print('this is printed on stdout')
print('this is also printed on stdout', file=sys.stderr)
Nota: stdout_redirected()mezcla E / S con búfer ( sys.stdoutgeneralmente) y E / S sin búfer (operaciones en descriptores de archivo directamente). Cuidado, podría haber problemas de almacenamiento en búfer .
Para responder, su edición: puede usar python-daemonpara demonizar su script y usar el loggingmódulo (como sugirió @ erikb85 ) en lugar de printdeclaraciones y simplemente redireccionar stdout para su script Python de larga ejecución que ejecuta nohupahora.
script.p > file