立即将 Python stdout 写入文件

立即将 Python stdout 写入文件

当尝试将 Python 脚本中的 stdout 写入文本文件 ( python script.py > log) 时,该文本文件会在命令启动时创建,但实际内容要等到 Python 脚本完成后才会写入。例如:

脚本.py:

import time
for i in range(10):
    print('bla')
    time.sleep(5)

当使用 调用时,每 5 秒打印到标准输出python script.py,但是当我调用 时python script.py > log,日志文件的大小保持为零,直到脚本完成。是否可以直接写入日志文件,以便您可以跟踪脚本的进度(例如使用tail)?

编辑事实证明,这python -u script.py确实有效,我不知道标准输出的缓冲。

答案1

发生这种情况是因为通常当进程 STDOUT 重定向到终端以外的其他位置时,输出会缓冲到某个特定于操作系统的大小的缓冲区(在许多情况下可能是 4k 或 8k)。相反,当输出到终端时,STDOUT 将进行行缓冲或根本不缓冲,因此您将在每个字符之后\n或每个字符看到输出。

您通常可以使用以下命令更改 STDOUT 缓冲stdbuf公用事业:

stdbuf -oL python script.py > log

现在,如果您tail -F log这样做,您应该会在生成时立即看到每行输出。


或者,在每次打印后显式刷新输出流应该达到相同的效果。看起来像sys.stdout.flush()应该在 Python 中实现这一点。如果您使用的是 Python 3.3 或更高版本,该print函数还有一个flush关键字可以执行此操作:print('hello', flush=True)

答案2

这应该可以完成这项工作:

import time, sys
for i in range(10):
    print('bla')
    sys.stdout.flush()
    time.sleep(5)

stdout由于Python默认会缓冲,这里我使用了sys.stdout.flush()刷新缓冲区。

另一种解决方案是使用 的-u(无缓冲)开关python。因此,以下操作也可以:

python -u script.py >> log

答案3

使用 python 自己的无缓冲输出选项的主题的变体是用作#!/usr/bin/python -u第一行。

由于#!/usr/bin/env python这个额外的参数不起作用,因此,可以选择运行PYTHONUNBUFFERED=1 ./my_scriipt.py > output.txt或分两步执行:

$ export PYTHONUNBUFFERED=1
$ ./myscript.py

答案4

您应该传递flush=Trueprint功能:

import time

for i in range(10):
    print('bla', flush=True)
    time.sleep(5)

根据文档,默认情况下,print不强制执行任何有关刷新的操作:

输出是否缓冲通常由文件决定,但如果 flush关键字参数为 true,则强制刷新流。

sys的 strems的文档说:

交互时,标准流是行缓冲的。否则,它们像常规文本文件一样被块缓冲。您可以使用-u命令行选项覆盖该值。


如果你被旧版本的 python 困住了,你必须调用flush的方法sys.stdout溪流:

import sys
import time

for i in range(10):
    print('bla')
    sys.stdout.flush()
    time.sleep(5)

相关内容