2009-09-25 10 views
25

मुझे पायथन में "पूंछ-एफ" अनुकरण करने की आवश्यकता है, लेकिन मैं रीडिंग लूप में time.sleep का उपयोग नहीं करना चाहता। मैं कुछ प्रकार के अवरुद्ध पढ़ने की तरह कुछ और सुरुचिपूर्ण चाहता हूं, या चयन करें। टाइमआउट के साथ चयन करें, लेकिन पायथन 2.6 "चयन करें" प्रलेखन विशेष रूप से कहता है: "यह नियमित फाइलों पर यह निर्धारित करने के लिए नहीं किया जा सकता है कि फाइल आखिरकार पढ़ी गई है या नहीं। " कोई अन्य तरीका? कुछ दिनों में यदि कोई समाधान नहीं दिया जाता है तो मैं इसे समझने के लिए पूंछ के स्रोत स्रोत को पढ़ूंगा। मुझे आशा है कि वे नींद का उपयोग नहीं करेंगे, हे धन्यवाद।tail -f में अजगर के साथ कोई समय नहीं। नींद

MarioR

+0

नींद में समस्या क्या है? –

+0

बीटीडब्ल्यू, यदि आप क्रॉस प्लेटफ़ॉर्म समाधान की तलाश करते हैं, और इस प्रकार 'popen ("tail -f'% s ''% filename)' का उपयोग नहीं करते हैं, तो आपको अवगत होना चाहिए कि Windows पर फ़ाइल ऑब्जेक्ट्स चयन द्वारा स्वीकार्य नहीं हैं। चयन –

+2

पूंछ सी स्रोत नींद() का उपयोग करता है। कड़ाई से बोलते हुए, आपको * नींद की ज़रूरत नहीं है, लेकिन इसका उपयोग नहीं करने से आपके सीपीयू को 100% पर चिपकाया जाएगा। आसान समाधान का उपयोग क्यों नहीं करें? –

उत्तर

-2

आप क्यों नहीं बस tail पर ही subprocess.call का उपयोग नहीं करते?

subproces.call(['tail', '-f', filename]) 

संपादित करें: अतिरिक्त खोल प्रक्रिया को समाप्त करने फिक्स्ड।

EDIT2: फिक्स्ड os.popen पदावनत को खत्म करने और इस प्रकार, मानकों को जोड़ espaces और अन्य सामग्री से बचने, और फिर एक खोल प्रक्रिया को चलाने की जरूरत है।

+10

विंडोज़ पर कोई पूंछ –

+2

-1: पॉपन गलत तरीका है - यह केवल पूंछ कार्यक्रम चलाने के लिए आवश्यक एक नई खोल प्रक्रिया का आह्वान करता है। – nosklo

+0

नोस्क्लो: आप सही हैं। मैंने इसे निष्पादन का उपयोग करने के लिए तय कर दिया है। इस तरह आप कमांड लाइन पार्सिंग के लिए खोल का लाभ प्राप्त करते हैं, लेकिन अतिरिक्त प्रक्रिया का ओवरहेड नहीं है। –

10

फ़ाइल से पढ़ने पर, आपकी एकमात्र पसंद नींद (see the source code) है। यदि आप एक पाइप से पढ़ते हैं, तो आप आसानी से पढ़ सकते हैं क्योंकि जब तक डेटा तैयार नहीं होता है तब तक पढ़ा जाएगा।

इसका कारण यह है कि ओएस इस धारणा का समर्थन नहीं करता है कि "किसी को फ़ाइल में लिखने की प्रतीक्षा करें"। हाल ही में, कुछ फाइल सिस्टम ने एक एपीआई जोड़ा जहां आप फ़ाइल में किए गए बदलावों के लिए सुन सकते हैं लेकिन पूंछ इस एपीआई का उपयोग करने के लिए बहुत पुरानी है और यह हर जगह उपलब्ध नहीं है।

32

(अपडेट) या तो एफएस उपकरण

  • पर नज़र रखता है linux
  • लिए Mac

या एक भी नींद उपयोग (जो मैं आप के रूप में ज्यादा विचार किया जाएगा के लिए Windows

  • के लिए उपयोग करें और अधिक सुंदर)।

    import time 
    def follow(thefile): 
        thefile.seek(0,2)  # Go to the end of the file 
        while True: 
         line = thefile.readline() 
         if not line: 
          time.sleep(0.1) # Sleep briefly 
          continue 
         yield line 
    
    logfile = open("access-log") 
    loglines = follow(logfile) 
    for line in loglines: 
        print line 
    
  • +0

    हे, मैं लगभग उसी कोड को पोस्ट करने वाला था (हालांकि जनरेटर के रूप में नहीं, जो कि अधिक सुरुचिपूर्ण है), +1 – dbr

    +0

    क्यों नहीं यदि लाइन: उपज लाइन time.sleep (0.1) '? इससे अतिरिक्त नींद आ सकती है, लेकिन यह वास्तव में एक बड़ा सौदा नहीं है (मेरी राय में)। –

    +1

    यदि यह अतिरिक्त नींद का कारण बनता है, तो हाँ क्यों? –

    0

    IMO आप नींद का उपयोग करना चाहिए, यह सब मंच पर काम करता है और कोड सरल

    नहीं तो आप मंच विशिष्ट एपीआई जो आप बता सकते हैं का उपयोग कर सकते हो जाएगा जब फ़ाइल परिवर्तन उदा फ़ोल्डर पर खिड़की उपयोग FindFirstChangeNotification पर और FILE_NOTIFY_CHANGE_LAST_WRITE घटनाओं

    linux पर नजर मुझे लगता है कि आप i-notify

    उपयोग कर सकते हैं पर मैक OSX का उपयोग FSEvents

    -2

    आप सभी प्लेटफार्मों पर GLib का उपयोग कर सकते हैं, तो आप glib.io_add_watch का उपयोग करना चाहिए; तो आप एक सामान्य जीएलआईबी मेनलोप और घटनाओं को संसाधित कर सकते हैं जैसे कि वे किसी भी मतदान व्यवहार के बिना होते हैं।

    http://library.gnome.org/devel/pygobject/stable/glib-functions.html#function-glib--io-add-watch

    +0

    यह एक बार फ़ाइल के अंत में पढ़ने के लिए काम करेगा, लेकिन अतिरिक्त डेटा पढ़ने के लिए नहीं लिखा है। – daf

    0

    आप here देख सकते हैं करने के लिए कैसे एक "पूंछ -f" inotify का उपयोग कर की तरह:

    यह एक उदाहरण [वैसा] कैसे inotify मॉड्यूल, यह हो सकता है का उपयोग करने के दिखाने के लिए है हालांकि बहुत उपयोगी अपरिवर्तित हो।

    एक वॉचर उदाहरण आपको किसी भी फ़ाइल या निर्देशिका और उपनिर्देशिकाओं पर होने वाली किसी भी घटना के लिए कॉलबैक परिभाषित करने देता है।

    inotify मॉड्यूल पकाने की विधि से 576375

    +1

    आपके उत्तर में कोड शामिल होना चाहिए। इस बात की कोई गारंटी नहीं है कि लिंक अभी भी भविष्य में काम करेगा। –

    0

    अधिकांश कार्यान्वयनों मैं उपयोग readlines देखा है है()/नींद()। inotify या इसी तरह हो सकता है के आधार पर एक समाधान तेजी से हो लेकिन पर विचार करें:

    • एक बार libinotify आपको बताता है कि आप जिस फ़ाइल को readlines() वैसे भी
    • का उपयोग कर एक के खिलाफ readlines() कॉल खत्म होगा बदल गया है फ़ाइल जो बदली नहीं है, जो आप libinotify के बिना कर रहे हैं, पहले से ही एक बहुत तेज़ ऑपरेशन है:

      giampaolo @ ubuntu: ~ $ python -m timeit -s "f = open ('foo.py ',' आर '); f.read() "-c" f.readlines() " 1000000 लूप, 3 का सर्वश्रेष्ठ: 0.41 उपयोग प्रति लूप

    यह कहा है, पर विचार किसी भी libinotify के समान समाधान पोर्टेबिलिटी मुद्दों है कि, मैं readlines का उपयोग कर पर पुनर्विचार हो सकता है()/नींद()। देखें: http://code.activestate.com/recipes/577968-log-watcher-tail-f-log/

    11

    नींद के मुद्दों को कम करने के लिए मैंने टेजरी बार योचय के समाधान को संशोधित किया और अब गतिविधि होने पर और जल्दी से चुनाव नहीं होने पर कुछ सेकंड के बाद यह केवल हर सेकेंड में मतदान करता है।/ले जाया गया, लेकिन

    #include <unistd.h> 
    #include <sys/inotify.h> 
    
    int main() { 
        int inotify_fd = inotify_init(); 
        inotify_add_watch(inotify_fd, "/tmp/f", IN_MODIFY); 
        struct inotify_event event; 
        while (1) { 
         read(inotify_fd, &event, sizeof(event)); 
         [file has changed; open, stat, read new data] 
        } 
    } 
    

    यह सिर्फ एक कम से कम उदाहरण स्पष्ट रूप से त्रुटि जाँच की कमी है और नोटिस नहीं होगा जब फ़ाइल हटा दी जाती है वह यह है कि:

    import time 
    
    def follow(thefile): 
        thefile.seek(0,2)  # Go to the end of the file 
        sleep = 0.00001 
        while True: 
         line = thefile.readline() 
         if not line: 
          time.sleep(sleep) # Sleep briefly 
          if sleep < 1.0: 
           sleep += 0.00001 
          continue 
         sleep = 0.00001 
         yield line 
    
    logfile = open("/var/log/system.log") 
    loglines = follow(logfile) 
    for line in loglines: 
        print line, 
    
    0

    लिनक्स के लिए tail -f का सरलतम C कार्यान्वयन यह है यह पाइथन कार्यान्वयन की तरह दिखने के बारे में एक अच्छा विचार देना चाहिए।

    यहां एक उचित पायथन कार्यान्वयन है जो ऊपर उल्लिखित तरीके से inotify पर बात करने के लिए अंतर्निहित ctypes का उपयोग करता है।

    """ simple python implementation of tail -f, utilizing inotify. """ 
    
    import ctypes 
    from errno import errorcode 
    import os 
    from struct import Struct 
    
    # constants from <sys/inotify.h> 
    IN_MODIFY = 2 
    IN_DELETE_SELF = 1024 
    IN_MOVE_SELF = 2048 
    
    def follow(filename, blocksize=8192): 
        """ 
        Monitors the file, and yields bytes objects. 
    
        Terminates when the file is deleted or moved. 
        """ 
        with INotify() as inotify: 
         # return when we encounter one of these events. 
         stop_mask = IN_DELETE_SELF | IN_MOVE_SELF 
    
         inotify.add_watch(filename, IN_MODIFY | stop_mask) 
    
         # we have returned this many bytes from the file. 
         filepos = 0 
         while True: 
          with open(filename, "rb") as fileobj: 
           fileobj.seek(filepos) 
           while True: 
            data = fileobj.read(blocksize) 
            if not data: 
             break 
            filepos += len(data) 
            yield data 
    
          # wait for next inotify event 
          _, mask, _, _ = inotify.next_event() 
          if mask & stop_mask: 
           break 
    
    LIBC = ctypes.CDLL("libc.so.6") 
    
    
    class INotify: 
        """ Ultra-lightweight inotify class. """ 
        def __init__(self): 
         self.fd = LIBC.inotify_init() 
         if self.fd < 0: 
          raise OSError("could not init inotify: " + errorcode[-self.fd]) 
         self.event_struct = Struct("iIII") 
    
        def __enter__(self): 
         return self 
    
        def __exit__(self, exc_type, exc, exc_tb): 
         self.close() 
    
        def close(self): 
         """ Frees the associated resources. """ 
         os.close(self.fd) 
    
        def next_event(self): 
         """ 
         Waits for the next event, and returns a tuple of 
         watch id, mask, cookie, name (bytes). 
         """ 
         raw = os.read(self.fd, self.event_struct.size) 
         watch_id, mask, cookie, name_size = self.event_struct.unpack(raw) 
         if name_size: 
          name = os.read(self.fd, name_size) 
         else: 
          name = b"" 
    
         return watch_id, mask, cookie, name 
    
        def add_watch(self, filename, mask): 
         """ 
         Adds a watch for filename, with the given mask. 
         Returns the watch id. 
         """ 
         if not isinstance(filename, bytes): 
          raise TypeError("filename must be bytes") 
         watch_id = LIBC.inotify_add_watch(self.fd, filename, mask) 
         if watch_id < 0: 
          raise OSError("could not add watch: " + errorcode[-watch_id]) 
         return watch_id 
    
    
    def main(): 
        """ CLI """ 
        from argparse import ArgumentParser 
        cli = ArgumentParser() 
        cli.add_argument("filename") 
        args = cli.parse_args() 
        import sys 
        for data in follow(args.filename.encode()): 
         sys.stdout.buffer.write(data) 
         sys.stdout.buffer.flush() 
    
    if __name__ == '__main__': 
        try: 
         main() 
        except KeyboardInterrupt: 
         print("") 
    

    नोट ऐसे inotify, pyinotify और python-inotify के रूप में अजगर के लिए विभिन्न inotify एडेप्टर, देखते हैं कि। वे मूल रूप से INotify कक्षा का काम करेंगे।

    0

    sh नामक एक शानदार लाइब्रेरी थ्रेड ब्लॉक वाली फ़ाइल को पूंछ कर सकती है।

    for line in sh.tail('-f', '/you_file_path', _iter=True): 
        print(line) 
    
    संबंधित मुद्दे