[Tutor] Reset while loop

Alan Gauld alan.gauld at btinternet.com
Wed May 6 09:48:08 CEST 2009


"David" <david at abbottdavid.com> wrote


> I was playing around with trying to create a python program like tail -f 
> as discussed on the list. i came up with this;

Some general comments first:

> def tail_it(bufsize=8192, linesep=__import__('os').linesep):

No idea why you are using the import stuff,  just use os.linesep

>     f = None
>     if f == None:

This is redundant. You set f to None so the if test is always
true, so you don't need it.

>         f = open(tail_fname, 'rb')

Where is tail_fname defined? It would be sensible to make
it an input parameter.

>         f.seek(0, 2)
>         pos, tailsize = divmod(f.tell(), bufsize)
>         if tailsize == 0:
>             pos = max(0, pos-1)
>         pos *= bufsize

I got confused trying to work out exactly what this was doing.
pos is initially the number of times bufsize fits in the file, but
then gets modified to zero or one less than its current value.

>         f.seek(pos)
>         lines = f.read().split(linesep)
>         x = len(lines)
>         x = x-2
>         print lines[x:]

Could just be print lines[-2:]


>         f.close()

All of the above is repeated inside your while loop so
put it into a function and call the function inside the loop.


>     while True:
>         new_time = os.stat(tail_fname).st_mtime
>         if new_time > old_time:

Where is old_time defined?

You could call your new function here

>             f = open(tail_fname, 'rb')
>             f.seek(0, 2)
>             pos, tailsize = divmod(f.tell(), bufsize)
>             if tailsize == 0:
>                 pos = max(0, pos-1)
>             pos *= bufsize
>             f.seek(pos)
>             lines = f.read().split(linesep)
>             x = len(lines)
>             x = x-2
>             print lines[x:]

>             time.sleep(sec_to_wait)

And call this after the function

>             f.close()

> [output]
> ['May  5 22:32:26 opteron su[5589]: pam_unix(su:session): session closed 
> for user root', '']
> ['May  5 22:32:26 opteron su[5589]: pam_unix(su:session): session closed 
> for user root', '']
> ['May  5 22:40:01 opteron cron[22996]: (root) CMD (test -x 
> /usr/sbin/run-crons && /usr/sbin/run-crons )', '']
> ['May  5 22:41:26 opteron ntpd[3571]: kernel time sync status change 
> 4001', '']
> ['May  5 22:41:26 opteron ntpd[3571]: kernel time sync status change 
> 4001', '']
> [/output]
>
> That was with sec_to_wait set at 30
>
> The problem I am having is it will print something whatever sec_to_wait 
> is set to even if the file's st_mtime is the same. I want it to only 
> prine when the st_mtime has changed. I think I need to update the while 
> loop and make old_time = new-time and start over but I need some 
> direction to get started, thanks

You need to set the old time somewhere, it never changes in your code.
If you put the actual read/print code in a function (it would be better not
to have the print in there, just return the string to be printed. Then your
code would look like:

import os

def get_tail(fname, bufsize, linesep):
         f = open(fname, 'rb')
         f.seek(0, 2)
         pos, tailsize = divmod(f.tell(), bufsize)
         if tailsize == 0:
             pos = max(0, pos-1)
         pos *= bufsize
         f.seek(pos)
         lines = f.read().split(linesep)
         f.close()
         return lines[-2:]


def tail_it(fname, bufsize=8192, linesep=os.linesep):
     while True:
         new_time = os.stat(tail_fname).st_mtime
         if new_time > old_time:
             time.sleep(sec_to_wait)
             print get_tail (fname, bufsize, linesep)
         old_time = new_time

I haven't tried it but that should be close to what you want.


-- 
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/ 




More information about the Tutor mailing list