tcl exec result redirected to stdout need to be stored too
Lake a look at this two lines
case 1
set cvsUpdStr [exec cvs -qn upd]
case 2
set cvsUpdStr [exec cvs -qn upd >&@stdout]
For the first case cvsUpdStr
is the output of the command, but there is nothing printed out during command execution. For the second case the cvs upd
command output is printed on the screen, but cvsUpdStr
is empty. How to combine them so that it will print out the result of cvs upd
and also will store the same output in cvsUpdStr
variable?
There are two possibilities. Either run it as a pipeline (created with open |...
) and handle the messages as they come in by storing them and printing them, or use the Unix tee
utility. The second alternative is definitely simpler!
# I like to spell out “update” in full
set cvsUpdStr [exec cvs -qn update | tee /dev/tty]
The tee
program sends its standard input to its normal standard output plus the named file; we use /dev/tty
to send it to the current terminal.
Note however that you may get long delays in the output of cvs
due to it buffering its output. This is just the default behavior of the C library's I/O handling when sending output to a non-terminal, and can be a problem if you need the output instantly. Fixing this gets quite involved (you end up using Expect) so if you're happy with the output being bursty, just leave it alone…
On Windows, you need to do it the other way.
set pipe [open |[list cvs -qn update] "r"]
while {[gets $pipe line] >= 0} {
append cvsUpdStr "$linen" ;# Note the n at the end!
puts $line
}
close $pipe ;# Any errors turn up here!
The construct with |[list ...]
is rather unusual in Tcl terms, but it is the correct one to use in this situation. (If the first character of the “filename” to open
is a |
, the rest of the argument is treated as a list of arguments to use for building a pipeline.)