Có contextlib.redirect_stdout()
chức năng trong 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`')
Nó tương tự như:
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
có thể được sử dụng trên các phiên bản Python trước đó. Phiên bản thứ hai không thể tái sử dụng . Nó có thể được thực hiện một nếu muốn.
Nó không chuyển hướng thiết bị xuất chuẩn ở cấp độ mô tả tệp, ví dụ:
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'
và 'echo this also is not redirected'
không được chuyển hướng đến output.txt
tập tin.
Để chuyển hướng ở cấp mô tả tệp, os.dup2()
có thể được sử dụng:
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
Ví dụ tương tự hoạt động ngay bây giờ nếu stdout_redirected()
được sử dụng thay vì 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')
Đầu ra mà trước đây đã được in trên thiết bị xuất chuẩn bây giờ sẽ output.txt
miễn là trình stdout_redirected()
quản lý bối cảnh hoạt động.
Lưu ý: stdout.flush()
không xóa bộ đệm C stdio trên Python 3 trong đó I / O được triển khai trực tiếp trên các cuộc gọi read()
/ write()
hệ thống. Để xóa tất cả các luồng đầu ra C stdio đang mở, bạn có thể gọi libc.fflush(None)
một cách rõ ràng nếu một số tiện ích mở rộng C sử dụng I / O dựa trên 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
Bạn có thể sử dụng stdout
tham số để chuyển hướng các luồng khác, không chỉ sys.stdout
ví dụ: để hợp nhất sys.stderr
và sys.stdout
:
def merged_stderr_stdout(): # $ exec 2>&1
return stdout_redirected(to=sys.stdout, stdout=sys.stderr)
Thí dụ:
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)
Lưu ý: stdout_redirected()
trộn I / O được đệm ( sys.stdout
thường) và I / O không có bộ đệm (thao tác trên mô tả tệp trực tiếp). Coi chừng, có thể có vấn đề đệm .
Để trả lời, chỉnh sửa của bạn: bạn có thể sử dụng python-daemon
để tạo nền cho tập lệnh của mình và sử dụng logging
mô-đun (như @ erikb85 đã đề xuất ) thay vì các print
câu lệnh và chỉ chuyển hướng thiết bị xuất chuẩn cho tập lệnh Python chạy dài mà bạn đang sử dụng nohup
bây giờ.
script.p > file