stdin不应等待"CTRL+D
我有一个简单的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)
我建议在你的代码中加个注释,解释一下为什么不使用普通的迭代器。