2011-08-17 26 views
16

我有問題需要從標準輸入或管道讀取python時,管道是來自「打開」(不知道正確的名稱) 文件。如何從一個沒有結尾的管道在Python中讀取stdin

我爲例 pipetest.py:

import sys 
import time 
k = 0 
try: 
    for line in sys.stdin: 
     k = k + 1 
     print line 
except KeyboardInterrupt: 
    sys.stdout.flush() 
    pass 
print k 

我運行有繼續輸出,並經過一段時間

$ ping 127.0.0.1 | python pipetest.py 
^C0 

我沒有得到任何輸出按Ctrl + C的程序。 但如果我通過一個普通的文件去它的作品。

$ ping 127.0.0.1 > testfile.txt 

這是按Ctrl + C經過短暫的結束而

$ cat testfile.txt | python pipetest.py 

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.017 ms 
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.015 ms 
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.014 ms 
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.013 ms 
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.012 ms 

--- 127.0.0.1 ping statistics --- 
5 packets transmitted, 5 received, 0% packet loss, time 3998ms 
rtt min/avg/max/mdev = 0.012/0.014/0.017/0.003 ms 
10 

我怎樣做節目結束之前,在這種情況下,中國平安已經結束得到任何輸出?

回答

21

嘗試了下:

import sys 
import time 
k = 0 
try: 
    buff = '' 
    while True: 
     buff += sys.stdin.read(1) 
     if buff.endswith('\n'): 
      print buff[:-1] 
      buff = '' 
      k = k + 1 
except KeyboardInterrupt: 
    sys.stdout.flush() 
    pass 
print k 
+1

我很高興它的工作,但你肯定可以用`在stdin`行,只要你知道它會阻止,直到找到結束的行(這就是爲什麼你的版本的作品,`read`不會像那樣阻止)。 – agf 2011-08-17 10:55:49

+2

我不是建議你刪除你的答案,只是最後一行是錯誤的。我刪除了「完全錯誤」的評論,因爲它是錯誤的 - 你的程序是正確的,只是你的結語是錯誤的。我不是downvoter(我不會,因爲我不知道你的答案是否會起作用)。 – agf 2011-08-17 11:06:08

6
k = 0 
try: 
    while True: 
     print sys.stdin.readline() 
     k += 1 
except KeyboardInterrupt: 
    sys.stdout.flush() 
    pass 
print k 
+0

這不是與問題中的版本有同樣的問題嗎?我認爲readline會阻塞,直到找到一個`\ n`? – agf 2011-08-17 11:49:41

3

而sys.stdin是一個類似文件的對象,這意味着你可以在它的行迭代,它會阻止,直到EOF插入。

的行爲可以用下面的僞代碼來描述:

while True: 
    input = "" 
    c = stdin.read(1) 
    while c is not EOF: 
     input += c 
     c = stdin.read(1) 
    for line in input.split('\n'): 
     yield line 

這意味着,雖然你可以遍歷sys.stdin的線,你不能在手使用這種方法的任務,你必須明確地調用read()或readline()

3

這就是我最終這樣做的結果。我並不喜歡其他任何解決方案,但它們看起來並不像pythonic。

這將爲所有打開的文件輸入創建一個容器,以迭代所有行。這也將負責關閉上下文管理器末尾的文件。

我覺得這可能是for line in sys.stdin:塊應該默認運行的方式。

class FileInput(object):               
    def __init__(self, file):             
     self.file = file              

    def __enter__(self):               
     return self                

    def __exit__(self, *args, **kwargs):           
     self.file.close()              

    def __iter__(self):               
     return self                

    def next(self):                
     line = self.file.readline()            

     if line == None or line == "":           
      raise StopIteration             

     return line 

with FileInput(sys.stdin) as f: 
    for line in f: 
     print f 

with FileInput(open('tmpfile') as f: 
    for line in f: 
     print f 

從命令行以下兩個應該工作:

tail -f /var/log/debug.log | python fileinput.py 
cat /var/log/debug.log | python fileinput.py 
0

對於這一點沒有等到標準輸入流結束,您可以在readline的ITER工作。我認爲這是最簡單的解決方案。

import sys 
import time 
k = 0 
try: 
    for line in iter(sys.stdin.readline, b''): 
     k = k + 1 
     print line 
except KeyboardInterrupt: 
    sys.stdout.flush() 
    pass 
print k