Reputation: 4850
Say there is a file log.txt
and some kind of log is being appended to it permanently.
I want to track that file in the TCL environment.
I have tried this but it didn't worked.
set log [open log.txt a]
for { } { true } { update; after 1000 } {
# expected to get here the appended part
read $log
seek $log 0 end
}
Is it possible to read the modified file by the same file handle log
, or I have to close and re-open the file log.txt
?
Is there a kind of equivalent of Linux command tail -f
in TCL ?
Upvotes: 6
Views: 3427
Reputation: 10221
I have managed to write tail -f
equivalent on pure Tcl. The code is below:
proc readHandler {handle} {
puts -nonewline [read $handle]
flush stdout
# to reduce CPU overhead...
after 1000
}
set hFile [open "file.log" "r"]
# seek to the end of file if needed
# seek $hFile 0 end
fconfigure $hFile -buffering none -eofchar "" -blocking no
fileevent $hFile readable [subst {readHandler $hFile}]
#just for exiting into main event loop
vwait forever
Upvotes: 0
Reputation: 4382
You're not far off, just a few things to fix:
You only need the update command if your processing within the loop involves updating a gui or something else that requires the event loop - it's not needed for the code posted. Altogether this gives:
set log [open log.txt]
seek $log 0 end
for { } { true } { after 1000 } {
# expected to get here the appended part
puts -nonewline [read $log]
}
Upvotes: 0
Reputation: 55533
Just use tail
. It knows more that you about how to handle complicated cases (you can look at its source).
In one of my projects, I have something like this to monitor a trace file produced by a proprietary tool:
set fd [open [list | tail --follow=name --retry --lines 0 $opt(trace) 2>@1]]
chan event $fd readable [list FollowTrace $fd]
proc FollowTrace fd {
if {[gets $fd line] < 0} {
set code [catch {close $fd} err]
if {$code == 0} {
set ::result 0
} else {
puts stderr $err
set ::result 1
}
return
}
switch -regexp -matchvar parts -- $line {
{Tm_Session::Open.*FileName=([^,]+)} {
TryMakeLock [FullPathname [lindex $parts 1]]
}
{Tm_Session::Close.*FileName=([^,]+)} {
StartUpload [lindex $parts 1]
}
}
}
The general idea is that you spawn tail
on a given file then enter event loop and process tail
's output line-by-line.
Upvotes: 4