【问题标题】:Is there any way to have output piped line-by-line from a currently executing python program?有没有办法从当前正在执行的 python 程序中逐行输出管道?
【发布时间】:2013-02-11 16:11:57
【问题描述】:

当将 python 脚本的打印输出通过管道传输到 grep 等命令时,脚本的输出似乎仅在整个脚本完成后才通过管道传输到后续命令。

例如,在脚本test_grep.py 中,如下所示:

#!/usr/bin/env python
from time import sleep

print "message1"
sleep(5)
print "message2"
sleep(5)
print "message3"

当使用./test_grep.py | grep message 调用时,10 秒内什么都不会出现,此时所有三行都会出现。

将此与脚本test_grep.sh进行比较:

#!/usr/bin/env bash
echo "message1"
sleep 5 
echo "message2"
sleep 5
echo "message3"

./test_grep.sh | grep message 将立即输出 message1,然后每隔 5 秒输出一次 message2message3

我希望这是因为只有在 python 解释器完成执行后,输出才可用于下一个命令。有没有办法改变这种行为?

【问题讨论】:

  • 有趣的问题:)

标签: python bash grep pipe


【解决方案1】:

你可以做到的:

  • 通过在 python 中刷新每个print
  • 通过将标准输出设置为无缓冲
  • 通过将标准输出设置为行缓冲

您甚至可以调用python -u 来禁用缓冲。


我会选择行缓冲选项,因为它看起来最自然。

open(file, mode='r', buffering=-1 ....)

buffering 是一个可选整数,用于设置缓冲策略。 传递 0 关闭缓冲(仅在二进制模式下允许),1 到 选择行缓冲(仅在文本模式下可用)和一个大于 1 的整数 指示固定大小的块缓冲区的大小。

当您未指定缓冲(典型的“打开”)时,如果它检测到输出将直接执行 TTY(即到您的屏幕控制台),它将使用行缓冲。如果您通过管道输出或将其重定向到文件,它将切换回大型(4K / 8K)缓冲区。


你如何“将标准输出设置为行缓冲”?

您可以通过sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)重新打开stdout

【讨论】:

  • sys.stdout.flush() 完成这项工作。
  • 如何“将标准输出设置为行缓冲”?我在文件对象 (sys.stdout) 中找不到任何允许这样做的东西。也许通过标准输出的文件描述符(sys.stdout.fileno)?
  • 哇,很好的答案。使用#!/usr/bin/env python -u 有效,在每行之后调用sys.stdout.flush() 也是如此。我现在可能会选择前者,因为确保在每次打印后我都调用 flush 会变得笨拙。
猜你喜欢
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多