Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replicating "tail -f" with Python

According to David Beazley's talk on generators, the following code should replicate the UNIX tail -f command:

import time
def follow(thefile):
    thefile.seek(0,2)
    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

f = open('followed.txt')
lines = follow(f)

for i in lines:
    print i

If I run this in a shell, it's doing "something", and indeed it locks up the IPython notebook, but it ain't printing out the contents of followed.txt. Why so?

like image 639
Pyderman Avatar asked Mar 14 '23 12:03

Pyderman


2 Answers

I tried the script, it works.

You have to make sure your input file is a growing file. If not it is hanging and expecting new growing lines.

Here's a script keep writing line with timestamp into sample.csv every 5 seconds.

import os
import time
import datetime

while True:
    os.system("echo " + "sample line with timestamp:{0}".format(datetime.datetime.now()) + " >> " + " sample.csv")
    time.sleep(5)

Use your tail -f script to read it and you will see the output.

like image 88
Haifeng Zhang Avatar answered Mar 19 '23 02:03

Haifeng Zhang


The follow() generator is only going to return lines that are written to the file after follow() was called. The seek(0,2) puts the cursor at the end of the file, and then tries to read new lines from that point on.

tail usually outputs the last 10 lines by default. If you wanted something like that

def follow(thefile):
    n_lines = 0
    # Seek to the end of the file
    thefile.seek(0,2)
    # Seek the cursor back one character at a time until you
    # reach the beginning of the file or 10 newlines are found.
    while n_lines < 10 and thefile.tell() > 0:
        # Go back one character and read it.
        thefile.seek(-1, 1)
        c = thefile.read(1)
        # Only go back 10 lines
        if c == '\n':
            n_lines += 1:
        # Reset the cursor position for the character we just read
        thefile.seek(-1, 1)

    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line
like image 20
Brendan Abel Avatar answered Mar 19 '23 01:03

Brendan Abel