Il y a une contextlib.redirect_stdout()
fonction dans 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`')
C'est similaire à:
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
qui peut être utilisé sur les versions antérieures de Python. Cette dernière version n'est pas réutilisable . Il peut être fait si vous le souhaitez.
Il ne redirige pas la sortie standard au niveau des descripteurs de fichiers, par exemple:
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'
et 'echo this also is not redirected'
ne sont pas redirigés vers le output.txt
fichier.
Pour rediriger au niveau du descripteur de fichier, os.dup2()
pourrait être utilisé:
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
Le même exemple fonctionne maintenant si stdout_redirected()
est utilisé à la place 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')
La sortie qui était précédemment imprimée sur stdout va maintenant output.txt
tant que le stdout_redirected()
gestionnaire de contexte est actif.
Remarque: stdout.flush()
ne vide pas les tampons stdio C sur Python 3 où les E / S sont implémentées directement sur read()
/ les write()
appels système. Pour vider tous les flux de sortie stdio C ouverts, vous pouvez appeler libc.fflush(None)
explicitement si une extension C utilise des E / S basées sur 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
Vous pouvez utiliser un stdout
paramètre pour rediriger d'autres flux, non seulement sys.stdout
par exemple, pour fusionner sys.stderr
et sys.stdout
:
def merged_stderr_stdout(): # $ exec 2>&1
return stdout_redirected(to=sys.stdout, stdout=sys.stderr)
Exemple:
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)
Remarque: stdout_redirected()
mélange les E / S tamponnées ( sys.stdout
généralement) et les E / S non tamponnées (opérations sur les descripteurs de fichiers directement). Attention, il pourrait y avoir des problèmes de mise en mémoire tampon .
Pour répondre, votre modification: vous pouvez utiliser python-daemon
pour démonifier votre script et utiliser le logging
module (comme @ erikb85 l'a suggéré ) au lieu d' print
instructions et simplement rediriger stdout pour votre script Python de longue durée que vous exécutez nohup
maintenant.
script.p > file