web-dev-qa-db-ja.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が終了していますか?

26
Janne

次を試してください:

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
26

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
8
woot
k = 0
try:
    while True:
        print sys.stdin.readline()
        k += 1
except KeyboardInterrupt:
    sys.stdout.flush()
    pass
print k
7
codeape

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()を明示的に呼び出す必要があります。

4
ftartaggia

これは私がこれをやった方法です。他のソリューションはあまり好きではありませんでした。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
3
Kellen Fox