2011-08-17 2 views
16

파이프가 "열린"(올바른 이름을 모르는 경우) 파일 일 때 파이썬의 표준 입력 또는 파이프에서 읽는 데 문제가 있습니다.어떻게 끝나는 파이프에서 파이썬으로 파이썬에서 읽을합니까

나는이 예로 pipetest.py : 내가 가지고있는 출력 및 Ctrl + C 잠시

$ ping 127.0.0.1 | python pipetest.py 
^C0 

내가 더 출력을 얻을 후 계속 프로그램을 실행

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 > 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

다음을 시도하십시오 EOF가 삽입 될 때까지

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

내가이 일을 기뻐하지만 당신은 확실히 너무 오래 당신이'read'을 버전이 작동하는 이유 끝나는 라인 (찾을 때까지이 차단됩니다 알고, stdin'에서 라인'사용할 수 있습니다 그런 식으로 차단하지 않습니다.) – agf

+2

나는 당신이 당신의 대답을 삭제할 것을 제안하는 것이 아니라, 마지막 줄이 잘못되었다는 것을 제안합니다. 내가 잘못했기 때문에 "완전히 잘못된"의견을 삭제했습니다. 프로그램이 옳았으며, 귀하의 폐회사가 잘못되었습니다. 나는 downvoter 아니에요 (나는 당신의 대답이 효과가 있을지 모르겠다.). – agf

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

문제의 버전과 동일한 문제가 있지 않습니까? 나는'\ n'도 찾을 때까지 readline 블록을 생각합니까? – agf

+0

나는 그렇게 믿지 않는다. 예상대로 작동한다. – codeape

3

을 sys.stdin은 파일 - 류의 객체 동안, 당신은 그 라인을 반복 할 수 있습니다 의미가 차단됩니다.

동작은 다음 의사 코드로 설명 될 수

: 이것은 당신이 sys.stdin의 라인을 반복 할 수 있지만, 당신은 손에 작업에이 방법을 사용할 수 없습니다 당신이해야한다는 것을 의미

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 

명시 적으로 read() 또는 readline()을 호출하십시오.

3

이렇게하면 결국 이렇게됩니다. 나는 다른 해결책을 정말로 좋아하지 않았고, 그들은 매우 비단처럼 보이지 않았습니다.

이렇게하면 열린 파일 입력에 대한 컨테이너가 모든 행에서 반복됩니다. 또한 컨텍스트 관리자의 끝에서 파일을 닫는 작업도 처리합니다.

나는 이것이 아마도 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

stdin을 완전히 닫으시겠습니까? – Dannnno

+0

시스템 전체에서 stdin을 영구적으로 종료하지 않습니다. 프로그램과 파일 간의 연결을 닫고 있습니다. – raygozag

+1

@Kellen Fox - 당신은 당신의 소망을 얻었을 것입니다! http://stackoverflow.com/a/1454400/188963 https://docs.python.org/3/library/fileinput.html – abalter

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 
관련 문제