如何在Python中将标准输出重定向到任意文件?

When a long-running Python script (e.g, web application) is started from within the ssh session and backgounded, and the ssh session is closed, the application will raise IOError and fail the moment it tries to write to stdout. I needed to find a way to make the application and modules output to a file rather than stdout to prevent failure due to IOError. Currently, I employ nohup to redirect output to a file, and that gets the job done, but I was wondering if there was a way to do it without using nohup, out of curiosity.

我已经试过了。Stdout = open('somefile', 'w'),但这似乎并没有阻止一些外部模块仍然输出到终端(或者sys. exe)。Stdout =…Line根本没有开火)。我知道它应该在我测试过的更简单的脚本上工作,但我还没有时间在web应用程序上进行测试。


当前回答

其他答案不包括您希望分叉进程共享您的新标准输出的情况。

做那件事:

from os import open, close, dup, O_WRONLY

old = dup(1)
close(1)
open("file", O_WRONLY) # should open on 1

..... do stuff and then restore

close(1)
dup(old) # should dup to 1
close(old) # get rid of left overs

其他回答

import sys
sys.stdout = open('stdout.txt', 'w')

如果您想在Python脚本中进行重定向,请设置sys. exe。对文件对象的Stdout是有用的:

# for python3
import sys
with open('file', 'w') as sys.stdout:
    print('test')

一个更常见的方法是在执行时使用shell重定向(在Windows和Linux上相同):

$ python3 foo.py > file

正如@jfs提到的,大多数解决方案不能正确处理某些类型的stdout输出,例如来自C扩展的输出。在PyPI上有一个名为wurlitzer的模块负责处理所有这些。您只需要它的sys_pipes上下文管理器。简单易用:

from contextlib import redirect_stdout
import os
from wurlitzer import sys_pipes
        
log = open("test.log", "a")
with redirect_stdout(log), sys_pipes():
    print("print statement")
    os.system("echo echo call")

以下是Yuda Prawira的回答:

实现flush()和所有文件属性 将其编写为上下文管理器 也捕获stderr

.

import contextlib, sys

@contextlib.contextmanager
def log_print(file):
    # capture all outputs to a log file while still printing it
    class Logger:
        def __init__(self, file):
            self.terminal = sys.stdout
            self.log = file

        def write(self, message):
            self.terminal.write(message)
            self.log.write(message)

        def __getattr__(self, attr):
            return getattr(self.terminal, attr)

    logger = Logger(file)

    _stdout = sys.stdout
    _stderr = sys.stderr
    sys.stdout = logger
    sys.stderr = logger
    try:
        yield logger.log
    finally:
        sys.stdout = _stdout
        sys.stderr = _stderr


with log_print(open('mylogfile.log', 'w')):
    print('hello world')
    print('hello world on stderr', file=sys.stderr)

# you can capture the output to a string with:
# with log_print(io.StringIO()) as log:
#   ....
#   print('[captured output]', log.getvalue())

用其他语言(例如C)编写的程序必须使用特殊的魔法(称为双分叉)来明确地与终端分离(并防止僵尸进程)。所以,我认为最好的解决办法是模仿他们。

重新执行程序的一个好处是,你可以在命令行上选择重定向,例如/usr/bin/python mycoolscript.py 2>&1 1>/dev/null

查看这篇文章了解更多信息:在创建守护进程时执行双fork的原因是什么?