如何将stdout重定向到Python中的任意文件?
当从ssh会话中启动长时间运行的Python脚本(例如,Web应用程序)并进行后台处理,并且ssh会话关闭时,应用程序将引发IOError并在尝试写入stdout时失败 . 我需要找到一种方法来将应用程序和模块输出到文件而不是stdout,以防止由于IOError导致的失败 . 目前,我使用nohup将输出重定向到一个文件,这就完成了工作,但我想知道是否有办法在不使用nohup的情况下完成它,出于好奇 .
我已经尝试了 sys.stdout = open('somefile', 'w')
,但这似乎并没有阻止一些外部模块仍然输出到终端(或者 sys.stdout = ...
线根本没有触发) . 我知道它应该可以从更简单的脚本开始工作我还没有时间在Web应用程序上进行测试 .
11 回答
如果要在Python脚本中进行重定向,请将
sys.stdout
设置为文件对象可以解决问题:一种更常见的方法是在执行时使用shell重定向(在Windows和Linux上相同):
引自PEP 343 -- The "with" Statement(添加了import语句):
暂时重定向stdout:
使用如下:
当然,这不是线程安全的,但也不是手动执行相同的舞蹈 . 在单线程程序中(例如在脚本中),它是一种流行的处理方式 .
基于这个答案:https://stackoverflow.com/a/5916874/1060344,这是另一种我弄清楚我在其中一个项目中使用的方法 . 对于替换
sys.stderr
或sys.stdout
的任何内容,您必须确保替换符合file
接口,特别是如果您正在执行此操作,因为stderr / stdout用于不受您控制的其他库中 . 该库可能正在使用其他文件对象方法 .看看这种方式,我仍然让一切都去stderr / stdout(或任何文件),并使用Python的日志工具将消息发送到日志文件(但你可以真正做任何事情):
用其他语言(例如C)编写的程序必须明确地执行特殊魔法(称为双重分叉)以从终端分离(并防止僵尸进程) . 所以,我认为最好的解决方案是模仿它们 .
重新执行程序的一个优点是,您可以在命令行中选择重定向,例如
/usr/bin/python mycoolscript.py 2>&1 1>/dev/null
有关详细信息,请参阅此帖子:What is the reason for performing a double fork when creating a daemon?
@marcog
第二个选项只有当脚本在go中被执行时才有用 . 或者脚本应该完全执行然后输出进入该文件并且无限循环应该存在(最佳) . 最佳解决方案,如果它是一个简单的脚本
Python 3.4中有contextlib.redirect_stdout() function:
它类似于:
可以在早期的Python版本上使用 . 后一版本不是reusable . 如果需要,它可以制成一个 .
它不会将stdout重定向到文件描述符级别,例如:
b'not redirected'
和'echo this also is not redirected'
未重定向到output.txt
文件 .要在文件描述符级别重定向,可以使用
os.dup2()
:如果使用
stdout_redirected()
而不是redirect_stdout()
,则同样的示例现在有效:只要
stdout_redirected()
上下文管理器处于活动状态,之前在stdout上打印的输出现在变为output.txt
.注意:
stdout.flush()
不会刷新Python 3上的C stdio缓冲区,其中I / O直接在read()
/write()
系统调用上实现 . 要刷新所有打开的C stdio输出流,如果某些C扩展使用基于stdio的I / O,则可以显式调用libc.fflush(None)
:您可以使用
stdout
参数重定向其他流,而不仅仅是sys.stdout
,例如,合并sys.stderr
和sys.stdout
:例:
注意:
stdout_redirected()
混合缓冲I / O(通常为sys.stdout
)和无缓冲I / O(直接对文件描述符进行操作) . 要注意,可能有buffering issues .要回答,您的编辑:您可以使用python-daemon来守护您的脚本并使用
logging
模块(作为@erikb85 suggested)而不是print
语句,只是为您现在使用nohup
运行的长期运行的Python脚本重定向stdout .其他答案并未涵盖您希望分叉进程共享新stdout的情况 .
要做到这一点:
你需要像tmux或GNU screen这样的终端多路复用器
令我感到惊讶的是,Ryan Amos对原始问题的一个小评论是唯一提到的解决方案,远远优于所有其他提供的解决方案,无论python技巧多么聪明以及他们收到了多少赞成 . 除了Ryan的评论,tmux是GNU屏幕的一个很好的替代品 .
但原则是一样的:如果你发现自己想要在登出时离开终端工作,去咖啡馆吃三明治,去洗手间,回家(等)然后重新连接到你的终奌站从任何地方或任何计算机进行会话,就像你从未离开过一样,终端多路复用器就是答案 . 将它们视为用于终端会话的VNC或远程桌面 . 其他任何东西都是变通方法 . 作为奖励,当老板和/或合作伙伴进来并且您无意中使用其狡猾的内容而不是您的终端窗口而不是您的浏览器窗口时,您将不会丢失最后18个小时的处理时间!
以下是Yuda Prawira的变化答案:
实现
flush()
和所有文件属性将其写为上下文管理器
捕获
stderr
也.
你可以试试这个太好了