当尝试将 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=True
给print
功能:
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)