From: "James F.Hranicky" Date: 2002-08-01T21:50:03+09:00 Subject: Re: A very basic tail -f implementation This is a multi-part message in MIME format. --Multipart_Thu__1_Aug_2002_08:49:58_-0400_021187e8 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit On Thu, 1 Aug 2002 21:23:09 +0900 "Berger, Daniel" wrote: > > - Check for rotation by checking for changes in the inode number > > This is proving difficult in practice because, as the Pickaxe says, the > File::Stat info is recorded at the moment the File::Stat object is created; > changes made to the file after that point will not be reflected. This > applies to filehandles as well, as experimentation has shown. Simply > calling the class method won't work either because that requires the > filename which, by that point, has already changed. > > If I'm doing something wrong, I'd love to know how to make this work! That's true, you just have to stat the actual filename everytime and check against the current filehandle. I wrote my own very simple tail -f thingy in Ruby a few months back, and was recently working on improving it when I noticed that Florian released his version. Here's what I have so far. Anyone can use any of it however they want. ---------------------------------------------------------------------- | Jim Hranicky, Senior SysAdmin UF/CISE Department | | E314D CSE Building Phone (352) 392-1499 | | jfh@cise.ufl.edu http://www.cise.ufl.edu/~jfh | ---------------------------------------------------------------------- "Given a choice between a complex, difficult-to-understand, disconcerting explanation and a simplistic, comforting one, many prefer simplistic comfort if it's remotely plausible, especially if it involves blaming someone else for their problems." -- Bob Lewis, _Infoworld_ --Multipart_Thu__1_Aug_2002_08:49:58_-0400_021187e8 Content-Type: text/plain; name="t.txt" Content-Disposition: attachment; filename="t.txt" Content-Transfer-Encoding: 7bit #!/local/bin/ruby class Tail TAIL_TOP = 1 TAIL_END = 2 TAIL_SEEK = 3 def initialize(filename, seek, whence) @filename = filename begin @fileh = File.open(filename) rescue Errno::ENOENT retry end @ino = @fileh.stat.ino @ino_changed = false case whence when TAIL_TOP raise "Must specify non-negative number for TAIL_TOP" unless seek >= 0 wind(seek) when TAIL_END raise "Must specify non-positive number for TAIL_END" unless seek <= 0 rewind(seek) when TAIL_SEEK raise "Invalid file position #{seek} for file #{@filename}" unless seek >= 0 && seek <= @fileh.stat.size @fileh.seek(seek, IO::SEEK_SET) else raise "Invalid value for whence #{whence}" end end def wind(lines) @fileh.seek(0, IO::SEEK_SET) numlines = 0 0.upto(@fileh.stat.size) { |filepos| @fileh.seek(filepos, IO::SEEK_SET) return if (numlines == lines) i = @fileh.getc c = sprintf("%c", i) numlines += 1 if (c == "\n") } end def rewind(lines) @fileh.seek(0, IO::SEEK_END) lines = lines.abs numlines = 0 size = @fileh.stat.size - 1 size.downto(0) { |filepos| next if (size == filepos) @fileh.seek(filepos, IO::SEEK_SET) i = @fileh.getc c = sprintf("%c", i) numlines += 1 if (c == "\n") return if (numlines == lines) } end def gets loop { while (@fileh.eof?) begin if ((ino = File.stat(@filename).ino) != @ino) @ino_changed = true end rescue Errno::ENOENT retry end if (@ino_changed) @fileh.close initialize(@filename, 0, TAIL_TOP) @ino_changed = false next end sleep .5 @fileh.seek(0, IO::SEEK_CUR) end line = @fileh.gets if block_given? yield line else return line end } end end def Main tail = Tail.new(ARGV.shift, -10, Tail::TAIL_END) tail.gets { |line| print line } # while (line = tail.gets) # print line # end end Main() --Multipart_Thu__1_Aug_2002_08:49:58_-0400_021187e8--