答案其实很简单
close stdout open $file "w" ;# Now, stdout is redirected to $file puts hello close stdout open /dev/tty ;# Now, stdout recover to default puts hello
而背后的道理可以参见 Tcl_StandardChannels
简单概括一下如下。
当stdin/stdout/stderr被关闭(close)后,再次调用Tcl_CreateChannel时会按照stdin、stdout、stderr的顺序初始化standard channes。这就是开始的代码可以工作的原因。