From: Daniel Berger Date: 2002-08-01T23:43:45+09:00 Subject: tail - latest incarnation Hi all, Here's the latest incarnation I've come up with, stealing bits of code from James Hranicky and ideas from Curt Sampson. The inode and dev checks are untested, so if there's a logic flaw there, please let me know. Opions & feedback welcome/desired. Regards, Dan # Da code! class Tail < File def initialize(file,sleeptime=10) @filename = file @fh = File.open(file,"r") @sleeptime = sleeptime @ino = @fh.stat.ino @dev = @fh.stat.dev @ino_changed = false @dev_changed = false end ############################################################## # In block form, read a line at a time in a loop. Otherwise, # just return the number of lines specified as an array. ############################################################## def tail(max=10) if block_given? yield get_lines(max) loop do line = @fh.gets yield line unless line.nil? if @fh.eof? check_move() if (@ino_changed == true) || (@dev_changed == true) @fh.close initialize(@filename,@sleeptime) next end @fh.seek(@fh.pos) end sleep @sleeptime end else get_lines(max) end end def check_move begin if(File.stat(@filename).ino != @ino) @ino_changed = true end if(File.stat(@filename).dev != @dev) @dev_changed = true end rescue Errno::ENOENT retry end end ####################################################################### # Grab the last 'max' lines (default is 10). This method was created # for two reasons. First, even a "tail -f" reads the last 10 lines. # Second, it's separated from the tail() method in the event the # programmer just wants a "plain" tail. ####################################################################### def get_lines(max) @fh.seek(0,IO::SEEK_END) newline_count = 0 while newline_count < max begin @fh.pos -= 2 rescue Errno::EINVAL break end break if @fh.eof? if @fh.getc.chr == "\n" newline_count += 1 end end @fh.readlines end end