Generally, I'd recommend the stdout redirection that Donal Fellows suggests in his answer.
Sometimes this may not possible. Maybe the Tcl interpreter is linked into a complex application that has itself a fancy idea of where the output should go to, and then you don't know how to restore the stdout channel.
In those cases you can try to redefine the puts
command. Here's a code example on how you could do that. In plain Tcl, a command can be redefined by renaming it into a safe name, and creating a wrapper proc that calls the original command at the safe name - or not at all, depending on your intended functionality.
proc redirect_file {filename cmd} {
rename puts ::tcl::orig::puts
set mode w
set destination [open $filename $mode]
proc puts args "
uplevel \"::tcl::orig::puts $destination \$args\"; return
"
uplevel $cmd
close $destination
rename puts {}
rename ::tcl::orig::puts puts
}
You can also redirect text into a variable:
proc redirect_variable {varname cmd} {
rename puts ::tcl::orig::puts
global __puts_redirect
set __puts_redirect {}
proc puts args {
global __puts_redirect
set __puts_redirect [concat $__puts_redirect [lindex $args end]]
set args [lreplace $args end end]
if {[lsearch -regexp $args {^-nonewline}]<0} {
set __puts_redirect "$__puts_redirect\n"
}
return
}
uplevel $cmd
upvar $varname destination
set destination $__puts_redirect
unset __puts_redirect
rename puts {}
rename ::tcl::orig::puts puts
}
The Tcl'ers Wiki has another interesting example of redefining puts
in more complex applications. Maybe this is inspiring as well.