Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

looking for tcl equivalent of tail -f

339 views
Skip to first unread message

Bryan Oakley

unread,
Sep 19, 1996, 3:00:00 AM9/19/96
to

I really don't want to reinvent the wheel here. I need to be able to
follow the output of a file much like tail -f. This is some
functionality I'm adding to an existing tk4.0 program. I want to call a
proc that displays messages in a text widget as soon as possible after
they are posted to a file. I have a GUI that is monitoring a file
created by some other non-tk program so I can't just do a gets, waiting
for input. The GUI needs to remain functional.

Anybody have code that does this? Obviously I could poll the file on a
regular basis, but I would rather use something more clever using
fileevent or something. So, I'm looking for the easy way out.

--
Bryan Oakley, Software Engineer
Healthcare Communications, Inc.
oak...@healthcare.com

Tom Halliley

unread,
Sep 23, 1996, 3:00:00 AM9/23/96
to

How about:


set tail_f [open {| your_text_producing_command_here } r]

while { ! [eof $tail_f] } {
gets $tail_f one_line

append_to_your_text_widget $one_line
}


You might want to check the return code on gets too.

TomH


-------------------------------------------------------------------
J. Thomas Halliley | Principal Software Engineer | 619.824.0348
to...@thomsoft.com | Aonix | San Diego, CA

Peter Ruczynski

unread,
Sep 24, 1996, 3:00:00 AM9/24/96
to Bryan Oakley, rucz...@x500.bt.co.uk

Bryan Oakley wrote:
>
> I really don't want to reinvent the wheel here. I need to be able to
> follow the output of a file much like tail -f. This is some

If you're using expect then it's easy:

spawn -open [open "|tail -f /tmp/foo"]
expect_background -re .+ { your action here }

Otherwise the following will do the trick, unfortuantely
it is a poll solution. I have yet to see a working
solution using fileevent. Perhaps one is now available
but there were problems with it the last time I did
this sort of thing.

#!/usr/local/bin/wish
wm title . "Tail"
text .text -height 40 -setgrid 1
pack .text -expand 1 -fill both

set fp [open tail.dat RDONLY]
after 1000 doit .text $fp

proc doit {w fp} {
while {[gets $fp line] != -1} {
$w insert end [append line \n]
}
$w see end
after 1000 "doit $w $fp"
}

Hope this helps
Pete.
--
Peter Ruczynski
work: rucz...@x500.bt.co.uk
home: pe...@softbase.co.uk
play: http://www.softbase.co.uk/as

Bryan Oakley

unread,
Sep 25, 1996, 3:00:00 AM9/25/96
to Tom Halliley

Tom Halliley wrote:
>
> How about:
>
> set tail_f [open {| your_text_producing_command_here } r]

Nope. Absolutely impossible. The process that produces text is a daemon
process that is continuously running. I want to tail the log file of
this process. I do not have the option of starting the program from my
script.

Thanks, anyway. I've determined that a simple polling solution will work
best.

Donal K. Fellows

unread,
Sep 26, 1996, 3:00:00 AM9/26/96
to

In article <32495FEC...@healthcare.com>,

Bryan Oakley <oak...@healthcare.com> wrote:
> Tom Halliley wrote:
>> How about:
>> set tail_f [open {| your_text_producing_command_here } r]
>
> Nope. Absolutely impossible. The process that produces text is a daemon
> process that is continuously running. I want to tail the log file of
> this process. I do not have the option of starting the program from my
> script.
>
> Thanks, anyway. I've determined that a simple polling solution will work
> best.

Eh? Surely you could just use `tail -f' as your text producing
command, and then treat it as an ordinary text-stream-producing
process? GNU tail is certainly happy to output to an ordinary pipe
(I've just tested this under SunOS... :^)

Donal.
--
Donal K. Fellows http://r8h.cs.man.ac.uk:8000/ (SAY NO TO COMMERCIAL SPAMS!)
(work) fell...@cs.man.ac.uk Dept. Comp. Sci, Univ. Manchester, U.K.
| do...@ugglan.demon.co.uk 6,Randall Place, Heaton, Bradford, U.K. (home)
+-> ++44-161-275-6137 Send correspondence to my office ++44-1274-401017 <-+

wi...@news.sns-felb.debis.de

unread,
Sep 26, 1996, 3:00:00 AM9/26/96
to

Bryan Oakley (oak...@healthcare.com) wrote:
: Tom Halliley wrote:
: >
: > How about:
: >
: > set tail_f [open {| your_text_producing_command_here } r]
:
: Nope. Absolutely impossible. The process that produces text is a daemon
: process that is continuously running. I want to tail the log file of
: this process. I do not have the option of starting the program from my
: script.
:
: Thanks, anyway. I've determined that a simple polling solution will work
: best.
:
: --

: Bryan Oakley, Software Engineer
: Healthcare Communications, Inc.
: oak...@healthcare.com

I wonder what you expect as solution instead of polling the
file. Under UNIX (and that was the original home of Tcl/Tk)
there is no other possibility for real files than polling.
Real files are guaranteed to never block. So the I/O
multiplexer select(2) will report them readable at any time.
Maybe the next read(2) will get EOF.

And that is why tail(1) with option '-f' under UNIX in fact
polls the file after a delay of one second. This is done by
seeking to the last known size of the file and trying to read
more data. The seek(2) resets the EOF condition of the file
and if the file hasn't grown the read(2) would report EOF
again. So tail(1) sleeps another second and does that again
and again and again.

So you have exactly two possibilities in Tcl:

Create a command pipe (pipes are known to be blocking by
default) and use the real tail(1) in the command. Then use
fileevent to get the data.

Or (what I would prefer) do the polling yourself with the
following code.

#!/usr/bin/tclsh7.5

proc tail_f {fid} {
while {![eof $fid]} {
set data [read $fid]

# The following should be replaced by your
# own log analyzing code.
puts -nonewline $data

# Be warned - incomplete lines are already here.
# So your analyzing must be smart enough.
flush stdout
}

seek $fid [tell $fid] start

after 100 "tail_f $fid"
}

set logfid [open "./logfile" r]

# Maybe you only want messages from now on
seek $logfid 0 end

# Start watching the file
after 100 "tail_f $logfid"

# Just for Tcl
vwait forever

Doing the polling yourself is IMHO better because you have
platform independent code and you can control the polling
interval as needed.


Until later, Jan

--
#define OPINIONS "they are all mine - not those of debis or daimler-benz"

#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me. #
#================================== wi...@sapserv.debis.de (Jan Wieck) #

John Haxby

unread,
Oct 1, 1996, 3:00:00 AM10/1/96
to
Bryan Oakley wrote:
> Tom Halliley wrote:
> > How about:
> >
> > set tail_f [open {| your_text_producing_command_here } r]
>
> Nope. Absolutely impossible. The process that produces text is a
> daemon process that is continuously running. I want to tail the log
> file of this process. I do not have the option of starting the program
> from my script.

You might like the attached: it does a slightly better job than tail -f
in that it copes with files being truncated and even removed. Although
it can, in principle, "tail-f" arbitrarily meny files at once the screen
layout won't realistically handle more than about a dozen. You might
want to change comment out the initial tk_setPalette and change the
button font option if you aren't using CDE. Some of the colours are
hard coded as well, but it illustrates the technique.

--
John Haxby
These are my opinions, not my employer's.

ntail

Bryan Oakley

unread,
Oct 2, 1996, 3:00:00 AM10/2/96
to

Donal K. Fellows wrote:
>
> In article <32495FEC...@healthcare.com>,
> Bryan Oakley <oak...@healthcare.com> wrote:
> > Tom Halliley wrote:
> >> How about:
> >> set tail_f [open {| your_text_producing_command_here } r]
> >
> > Nope. Absolutely impossible. The process that produces text is a daemon
> > process that is continuously running. I want to tail the log file of
> > this process. I do not have the option of starting the program from my
> > script.
> >
> > Thanks, anyway. I've determined that a simple polling solution will work
> > best.
>
> Eh? Surely you could just use `tail -f' as your text producing
> command, and then treat it as an ordinary text-stream-producing
> process? GNU tail is certainly happy to output to an ordinary pipe
> (I've just tested this under SunOS... :^)

I see your point -- I obviously misunderstood the original poster, I
guees. Either that, or you have ;-)

Obviosly I *can* do this. The question is one of efficiency. As a rule I
try to avoid execing other programs like the plague. Why fire up a whole
'nother process just to read a file? Plus, as everyone else has so
kindly pointed out, tail -f simply polls the file every N seconds. So,
it's just much cleaner, portable, and faster to do the polling myself.

Finally, we're porting to NT (a big unknown to me) and I don't know if
NT has a native "tail" program. I work on a commercial program, so if NT
doesn't have a "tail -f" we would have to install and support one. No
thanks.

Anyway, the problem is solved.

0 new messages