This is a more efficient implementation of the tailf functionality based on the tcl-inotify package. It has the advantage that it doesn't suffer from polling overhead as the other implementations. Inotify asynchronously informs tailf of write changes in a file.
#!/bin/tclsh # An efficient tailf implementation using inotify package require inotify package provide tailf namespace eval tailf { namespace export add rem array set File2wd {} array set Wd2info {} inotify create ::tailf::watch ::tailf::handler proc getpos {filepath} { set fd [open $filepath r] seek $fd 0 end set pos [tell $fd] close $fd return $pos } proc handler {args} { variable File2wd variable Wd2info set events [watch read] foreach {wd flags cookie filepath} $events { if {! [info exists Wd2info($wd)]} { return } set diff {} set callback [lindex $Wd2info($wd) 1] set filepath [lindex $Wd2info($wd) 2] set old [lindex $Wd2info($wd) 0] set new [getpos $filepath] set Wd2info($wd) [lreplace $Wd2info($wd) 0 0 $new] if {$new < $old} { set old 0 } if {$old != $new} { set fd [open $filepath r] seek $fd $old while {[gets $fd line] >= 0} { append diff "$line" "\n" } close $fd } eval [list $callback $filepath $diff] } return } proc add {filepath callback} { variable File2wd variable Wd2info if {[file exists $filepath] && [file isfile $filepath]} { set pos [getpos $filepath] set wd [watch add $filepath {w}] set File2wd($filepath) $wd set Wd2info($wd) [list $pos $callback $filepath] } else { error "is either not a file, or does not exist" } } proc rem {filepath} { variable File2wd variable Wd2info if {! [info exists ::tailf::File($filepath)]} { error "$filepath is not monitored, or watch has been removed" } set wd $File2wd($filepath) unset Wd2info($wd) unset File2wd($filepath) watch del $filepath } } ;# namespace end
proc puts_hdlr {filepath diff} { puts -nonewline $diff } ::tailf::add "delme.txt" puts_hdlr set a {} vwait a
fr - 2010-09-29 08:46:34
inotify 1.3 with 8.6b1.1 requires changes in proc handler
set events [join [watch read]] foreach {k wd k flags k cookie k filepath} $events {