为了账号安全,请及时绑定邮箱和手机立即绑定

将stdout重定向到Python中的文件?

将stdout重定向到Python中的文件?

烙印99 2019-06-01 10:35:15
将stdout重定向到Python中的文件?如何将stdout重定向到Python中的任意文件?当一个长期运行的Python脚本(例如,web应用程序)从ssh会话内部启动并备份,而ssh会话被关闭时,应用程序将在尝试写入stdout时引发ioError并失败。我需要找到一种将应用程序和模块输出到文件中的方法,而不是stdout,以防止因ioError而导致的失败。目前,我使用nohup将输出重定向到一个文件,这样就可以完成任务,但出于好奇,我想知道是否有一种不使用nohup的方法。我已经试过了sys.stdout = open('somefile', 'w'),但这似乎并不能阻止某些外部模块仍然输出到终端(或者可能阻止sys.stdout = ...线根本没有开火)。我知道它应该从我测试过的更简单的脚本中运行,但我还没有时间在Web应用程序上进行测试。
查看完整描述

4 回答

?
温温酱

TA贡献1752条经验 获得超4个赞

的确有contextlib.redirect_stdout()功能在Python3.4中:

from contextlib import redirect_stdoutwith open('help.txt', 'w') as f:
    with redirect_stdout(f):
        print('it now prints to `help.text`')

它类似于:

import sysfrom contextlib import contextmanager@contextmanagerdef 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

可以在早期的Python版本上使用。后一版本不是可重复使用..如果想要的话,可以做一个。

它不会在文件描述符级别重定向stdout,例如:

import osfrom 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''echo this also is not redirected'不重定向到output.txt档案。

若要在文件描述符级别重定向,os.dup2()可用于:

import osimport sysfrom contextlib import contextmanagerdef 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@contextmanagerdef 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

如果stdout_redirected()被使用,而不是redirect_stdout():

import osimport 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')

以前在stdout上打印的输出现在转到output.txt只要stdout_redirected()上下文管理器处于活动状态。

注:stdout.flush()不刷新Python 3上的C Stdio缓冲区,其中I/O是直接在Python 3上实现的read()/write()系统呼叫。要刷新所有打开的C Stdio输出流,可以调用libc.fflush(None)如果某些C扩展使用基于Stdio的I/O,则显式地:

try:
    import ctypes    from ctypes.util import find_libraryexcept ImportError:
    libc = Noneelse:
    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

你可以用stdout参数来重定向其他流,而不仅仅是sys.stdout例如,合并sys.stderrsys.stdout:

def merged_stderr_stdout():  # $ exec 2>&1
    return stdout_redirected(to=sys.stdout, stdout=sys.stderr)

例子:

from __future__ import print_functionimport syswith merged_stderr_stdout():
     print('this is printed on stdout')
     print('this is also printed on stdout', file=sys.stderr)

注:stdout_redirected()混合缓冲I/O(sys.stdout(通常)和未缓冲的I/O(直接对文件描述符的操作)。小心,可能会有缓冲 问题.

要回答,您的编辑:您可以使用python-daemon若要守护脚本并使用logging模块(AS)@erikb 85建议)而不是print语句,并仅重定向长期运行的Python脚本的stdout。nohup现在。


查看完整回答
反对 回复 2019-06-01
?
一只名叫tom的猫

TA贡献1906条经验 获得超3个赞

你可以试试这个更好

import sysclass Logger(object):
    def __init__(self, filename="Default.log"):
        self.terminal = sys.stdout
        self.log = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)sys.stdout = Logger("yourlogfilename.txt")print "Hello world !" # this is should be saved in 
        yourlogfilename.txt


查看完整回答
反对 回复 2019-06-01
?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

其他答案没有涵盖您希望分叉进程共享新标准输出的情况。

要做到这一点:

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 1close(old) # get rid of left overs


查看完整回答
反对 回复 2019-06-01
  • 4 回答
  • 0 关注
  • 1342 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信