2011-08-17 18 views
16

नहीं है जब पाइप को "ओपन" (सही नाम नहीं पता) फ़ाइल से मानक इनपुट या पाइप से पढ़ने में समस्या है।आप एक पाइप से पायथन में 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 

मैं एक कार्यक्रम है जारी है कि उत्पादन और Ctrl + ग थोड़ी देर

$ 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 

कैसे मैंने पहले कार्यक्रम, समाप्त हो जाती है इस मामले पिंग में समाप्त हो गया है किसी भी उत्पादन प्राप्त करने के लिए करते हैं?

उत्तर

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

+2

मैं सुझाव नहीं दे रहा हूं कि आप अपना जवाब हटा दें, बस आखिरी पंक्ति गलत थी। मैंने "पूरी तरह गलत" टिप्पणी हटा दी क्योंकि यह गलत था - आपका प्रोग्राम सही था, बस आपका समापन बयान गलत था। मैं डाउनवॉटर नहीं हूं (मैं नहीं होगा, क्योंकि मुझे नहीं पता था कि आपका जवाब काम करेगा या नहीं)। – agf

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

क्या इस प्रश्न में संस्करण के समान समस्या नहीं है? मुझे लगता है कि जब तक यह '\ n' भी नहीं मिलता है तब तक रीडलाइन ब्लॉक लगता है? – agf

+0

मुझे विश्वास नहीं है, यह अपेक्षा के अनुसार काम करता है। – codeape

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 की लाइनों पर पुनरावृति कर सकते हैं, तो आप इस दृष्टिकोण कार्य के लिए हाथ में उपयोग नहीं कर सकते हैं और आप चाहिए स्पष्ट रूप से पढ़ें() या 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

@ केलेन फॉक्स - आप अपनी इच्छा प्राप्त कर सकते हैं! http://stackoverflow.com/a/1454400/188963 https://docs.python.org/3/library/fileinput.html – abalter

0

इसके लिए इंतजार कर रहे हैं जब तक stdin धारा समाप्त हो जाती है, तो आप ReadLine पर आईटीईआर कर सकते हैं बिना काम करने के। मुझे लगता है कि यह सबसे आसान समाधान है।

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