Miro Samek
Miro Samek

Reputation: 1975

How can I send the output of a long-running program to stdout in tcl without fileevent?

I need to collect the output from a long running external program in Tcl. I can't use exec, because this would block until the other program has finished. So, I think I should open a pipe:

set pipe [open "|long_running_program" "r"]

but then it is not clear to me how to send the output to stdout. I'm using pure Tcl, without the event loop, so I can't use fileevent.

Upvotes: 1

Views: 500

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137567

What you should do is put the pipe into non-blocking mode. Then you can use read to get everything currently available on the pipe, ready to transfer to stdout. However, you'll need to figure out when to look for output yourself; the fileevent command is Tcl's solution for that, but that requires the use of an event loop. (You could start a temporary one via update or vwait, of course; using tclsh doesn't mean no event loop, but rather just means no default event loop.)

fconfigure $pipe -blocking 0

set data [read $pipe]
if {[eof $pipe]} {
    # Other side is finished; close the pipe?
} elseif {[fblocked $pipe]} {
    # No data available right now; try later
} else {
    # Print to stdout; use the newlines already in the data
    puts -nonewline $data
}

You should also be aware that many programs only deliver data in bursts when they're writing to a pipe. They change their behavior depending on whether they're writing to a pipe or to a terminal. This can matter a lot, especially if you're doing command automation; if it does to you, your best option is the Expect extension package.

Upvotes: 3

Related Questions