stdin不应等待"CTRL+D

2 投票
3 回答
838 浏览
提问于 2025-04-18 16:32

我有一个简单的Python脚本,它应该从标准输入(stdin)读取数据。

所以,如果我把一个程序的输出重定向到我的Python脚本的标准输入里。

但是,我的程序记录的内容只有在这个程序结束时,才会“到达”我的Python脚本。

其实我想要的是,能够在我的程序记录每一行内容时,就立即处理这些内容,而不是等到这个程序结束时才处理。

那么,我该怎么做呢?怎么才能让标准输入在处理数据时,不用等到按下CTRL+D或者文件结束符(EOF)呢?

示例

# accept_stdin.py
import sys
import datetime

for line in sys.stdin:
    print datetime.datetime.now().second, line

# print_data.py
import time

print "1 foo"
time.sleep(3)
print "2 bar"

# bash
python print_data.py | python accept_stdin.py

3 个回答

2

正如@user2357112所说,你需要使用:

for line in iter(sys.stdin.readline, ''):

接下来,你需要用 -u 这个标志来启动Python,这样可以让输入和输出立即刷新。

python -u print_data.py | python -u accept_stdin.py

你也可以在开头的那一行(shebang)里指定这个标志。

3

这也是你那个生产者程序的问题,也就是你把标准输出(stdout)传给你的Python脚本的那个程序。

其实,这个程序只是在打印内容,但从来没有刷新,所以它打印的数据会保存在程序内部的缓冲区里,而不是直接送到系统。

在你的 print_data.py 文件里的 print 语句后面加上 sys.stdout.flush() 这一行代码。

你在退出程序时能看到数据,因为程序在退出时会自动刷新。

想了解更多,可以看看 这个问题

5

就像所有的文件对象一样,sys.stdin 这个迭代器读取输入时是分块进行的;即使输入的一行已经准备好了,这个迭代器也会尝试读取到块大小或者文件结束(EOF)才会输出任何内容。你可以通过使用 readline 方法来解决这个问题,因为它不会有这样的行为:

while True:
    line = sys.stdin.readline()
    if not line:
        # End of input
        break
    do_whatever_with(line)

你可以把这个方法和 iter 的两个参数形式结合起来,使用一个 for 循环:

for line in iter(sys.stdin.readline, ''):
    do_whatever_with(line)

我建议在你的代码中加个注释,解释一下为什么不使用普通的迭代器。

撰写回答