A very basic tail -f implementation

From: Curt Sampson [mailto:cjs@cynic.net]

- Check for rotation by checking for changes in 

the inode number


That’s true, you just have to stat the actual filename everytime and
check against the current filehandle.

Right. You also ought to check the device number, in case the file
is somewhow moved to another device and ends up with the same inode
number. At least, that’s what I did when I added the ‘-F’ option
to tail(1) in NetBSD. Maybe I’m just anal-retentive. :slight_smile:

Heh. I came across that while reading some usenet posts on a similar
subject.

Also, you might want to check to see if the file has been shortened,
in case the writer truncates it and starts writing again at the
beginning.

Wow. Thorough.

Well, here’s what I had come up with so far, using one of Paul Brannan’s
posts as a starting point. Between all of us, we should have something
pretty good and thorough soon. :slight_smile:

class Tail < File

def initialize(file,sleeptime=10)
@file = File.open(file,“r”)
@sleeptime = sleeptime
end

···

-----Original Message-----
On Thu, 1 Aug 2002, James F.Hranicky wrote:

On Thu, 1 Aug 2002 21:23:09 +0900 > > “Berger, Daniel” djberge@qwest.com wrote:

##############################################################

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 = @file.gets
yield line unless line.nil?
if @file.eof?
@file.seek(@file.pos)
end
sleep @sleeptime
end
else
get_lines(max)
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)

  @file.seek(0,IO::SEEK_END)
  newline_count = 0
  while newline_count < max 

     begin
        @file.pos -= 2
     rescue Errno::EINVAL
        break
     end

     break if @file.eof?

     if @file.getc.chr == "\n"
        newline_count += 1
     end
  end

  @file.readlines

end
end

=begin
= Description
Tail - A pure-Ruby implementation of the ‘tail’ command. Tail is a
subclass of File.
= Overview
t = Tail.new(“somefile.txt”)

To imitate ‘tail -f’, use a block

t.tail do |line|
puts line
end

To simply grab the last X lines, don’t use a block

a = t.tail(20)
puts a

or even

t.tail(20).each{ |line| puts line }
=end