我需要通过pipe道实时吸收bash命令的输出。 例如
for i in $(seq 1 4); do echo $i; sleep 1; done | ./script.py
其中script.py有这个
for line in sys.stdin.readlines(): print line
我期望序列打印,因为它变得可用,但python脚本正在等待bash脚本结束之前继续。
我看了这个相关的答案,但是这并没有解决我的问题。 我如何去实现这个python?
第一个问题是readlines将所有行读入列表。 它不能这样做,直到所有行都存在,直到stdin达到EOF。
但是实际上你并不需要线条的列表 ,只是一些线条的迭代 。 像sys.stdin这样的文件已经是这样一个可迭代的了。 而且这是一个懒惰的行为,一旦它们可用,就会一次生成一行,而不是一次性生成它们。
所以:
for line in sys.stdin: print line
每当你发现自己到达readlines ,问问你自己是否真的需要它。 答案永远是否定的。 (当然,除非你想用一个参数来调用它,或者在一些有缺陷的不太像文件的对象上。)看到更多的文章被认为是愚蠢的。
但同时,还有第二个问题。 这并不是说Python正在缓冲它的stdin ,或者其他进程正在缓冲它的stdout ,但是文件对象迭代器本身正在做内部缓冲,这可能(取决于你的平台,但是在大多数POSIX平台上,通常会这样)防止你到第一行,直到EOF,或者至少读了很多行。
这是Python 2.x的一个已知问题,已经在3.x中修复了,但是除非你愿意升级,否则不能帮助你。
在命令行和环境文档以及大多数系统的手册页中提到了这个解决方案,但却被埋在了-u标志文档的中间:
请注意,xreadlines(),readlines()和文件对象迭代器(“sys.stdin中的行”)中有内部缓冲区,不受此选项的影响。 要解决这个问题,你需要在“while 1:”循环中使用“sys.stdin.readline()”。
换一种说法:
while True: line = sys.stdin.readline() if not line: break print line
要么:
for line in iter(sys.stdin.readline, ''): print line
对于另外一个问题,在这个答案中 ,Alex Martelli指出,你总是可以忽略sys.stdin并重新fdopen文件描述符。 这意味着你得到一个POSIX fd而不是C stdio句柄的包装。 但这对于这个问题既不必要也不足够,因为问题不在于C stdio缓冲,而在于file.__iter__缓冲与它的交互。
* Python 3.x不再使用C stdio库的缓冲; 它在io模块的类型中自己完成所有事情,这意味着迭代器可以共享文件对象本身正在使用的同一个缓冲区。 虽然io在2.x上也是可用的,但是它并不是您open的默认设置,或者是stdio文件句柄,这就是为什么它在这里没有帮助。
使用Python 2.7.9(可能所有的Python都是3.x之前的版本),这个就是你所期望的:
#!/usr/bin/python import sys while True: line=sys.stdin.readline() if not line: break print line
你也可以这样做:
#!/usr/bin/python import sys for line in iter(sys.stdin.readline, ''): print line
在Python 3.4.3上,你可以做一些不合常规的建议:
#!/usr/local/bin/python3 import sys for line in sys.stdin: print(line)
您也可以像Python 3一样使用io类重新打开sys.stdin:
#!/usr/bin/python import sys, io for line in io.open(sys.stdin.fileno()): print(line)
第一,第二和最后一个方法都在OS X上的Python 2.7.6和2.7.9和Python 3.4.3上工作; 第三种方法,只在Python 3上。
当前最有回报的答案实际上并没有回答这个问题,因为它不会打印输出。 像下面的代码应该做你想做的事情:
import sys def readline(): while True: res = sys.stdin.readline() if not res: break yield res for line in readline(): print line
在这里,我们不是等待readline来构造一个列表,而是读一行,然后产生这个值。 而且我们只是继续使用输入和yielding,直到流的结束由sys.stdin.readline()的空返回信号。