你怎么从没有结束的管道读取python中的stdin

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你怎么从没有结束的管道读取python中的stdin相关的知识,希望对你有一定的参考价值。

当管道来自“打开”(不知道正确的名称)文件时,我有问题从python中的标准输入或管道读取。

我有例如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

我运行了一段时间后继续输出和Ctrl + c的程序

$ ping 127.0.0.1 | python pipetest.py
^C0

我没有输出。但如果我通过一个普通的文件,它的工作原理。

$ 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

如何在程序结束之前获取任何输出,在这种情况下ping已经结束?

答案

尝试下一个:

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
另一答案

为了使其工作而不等待stdin流结束,您可以在readline上进行操作。我认为这是最简单的解决方案。

import sys
k = 0
try:
   for line in iter(sys.stdin.readline, b''):
      k = k + 1
      print line
except KeyboardInterrupt:
   sys.stdout.flush()
   pass
print k
另一答案
k = 0
try:
    while True:
        print sys.stdin.readline()
        k += 1
except KeyboardInterrupt:
    sys.stdout.flush()
    pass
print k
另一答案

虽然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()

另一答案

这就是我最终做到这一点的方式。我并不喜欢任何其他解决方案,它们似乎不是非常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

以上是关于你怎么从没有结束的管道读取python中的stdin的主要内容,如果未能解决你的问题,请参考以下文章

神秘 => 从管道读取错误:管道已结束。 (109, 0x6d)

如何从没有外部 IP 的 GCE VM 中读取存储桶?

从命名管道读取的 C 不会结束

命名管道(C#)

C 到 Python 管道 - 如何检测读取器访问

使用 awk sed 等。从没有结束标签的文件中解析字段