Python 标准输出缓存刷新与 tee

2 投票
3 回答
7903 浏览
提问于 2025-04-15 13:13

下面的代码在通过管道传递给tee的时候会出现“断开的管道”错误,但如果不通过管道传递就能正常工作:

#!/usr/bin/python
import sys
def testfun():
    while 1:
        try :
            s = sys.stdin.readline()
        except(KeyboardInterrupt) :
            print('Ctrl-C pressed')
            sys.stdout.flush()
            return
        print s

if __name__ == "__main__":
    testfun()
    sys.exit()

预期的输出应该是:

./bug.py 
Ctrl-C pressed

当通过管道传递给tee时,观察到的情况要么是出现“断开的管道”错误,要么根本没有输出,也就是说tee的标准输出上什么都没有,bug.log里也没有任何内容:

./bug.py | tee bug.log
Traceback (most recent call last):
  File "./bug.py", line 14, in <module>
    sys.stdout.flush()
IOError: [Errno 32] Broken pipe

这可能是什么原因呢?

3 个回答

5

这不是一个Python的问题,而是一个与命令行(shell)有关的问题。正如Brian所说,按下Ctrl-C会同时终止两个进程。解决这个问题的一种方法是使用命名管道:

mknod mypipe p
cat mypipe | tee somefile.log &
./bug.py > mypipe
9

不,按下 Ctrl-C 并不会同时结束两个进程。它只会结束 tee 这个进程,tee 进程结束后,会关闭你脚本和 tee 之间的管道,这样你的脚本就会因为管道断开而崩溃,并显示错误信息。

要解决这个问题,tee 有一个选项可以把 Ctrl-C 信号传递给它前面的进程:-i

你可以试试:man tee

./bug.py
^CCtrl-C pressed
./bug.py | tee log
^CTraceback (most recent call last):
  File "./bug.py", line 14, in <module>
    testfun()
  File "./bug.py", line 9, in testfun
    sys.stdout.flush()
IOError: [Errno 32] Broken pipe

./bug.py | tee -i log
^CCtrl-C pressed
4

当你按下 Ctrl-C 时,系统会同时结束两个进程(pythontee),并关闭它们之间的连接。

所以,当你在 python 进程中处理 Ctrl-C 并进行清空操作时,它会发现 tee 已经被结束,连接也不再存在。因此就会出现错误信息。

(顺便问一下,你期待日志中会有什么内容吗?我没有看到你的进程在退出时输出其他信息,除了清空操作。)

撰写回答