有时候重定向是得到执行信息的必要手段,比如我在调试某个程序时需要将调试的输出结果存放到某个文件中以便于日后查看。
1.close stdout
2.set stdout [open out.txt w]
我关闭并重定义了
stdout
,使其成为某个被打开文件的
channel
,那么执行
puts
事实上是完成了对于文本的写操作。在还有一些情况中,是将
stdout
的结果显示到比如
text
这样的
Tk
组件上,以上的办法显然是无能为力了。作为
stdout
本身必须是一个
channel
,它不能作为一个变量或者其他什么的,所以一个替代的办法是使用
Memchan
模块,以下是在
tcl
的
wiki
上的一段代码。
1.package require Tk
2.package require Memchan
3.
4.text .t
5..t tag configure stdout -font {Courier 10}
6..t tag configure stderr -font {Courier 10} -foreground red
7.pack .t
8.
9.# install new stdout
10.close stdout
11.set stdout [fifo]
12.fileevent $stdout readable ".t insert end \[read $stdout\] stdout; .t see end"
13.
14.# install new stderr
15.close stderr
16.set stderr [fifo]
17.fileevent $stderr readable ".t insert end \[read $stderr\] stderr; .t see end"
18.
19.# test it
20.puts "this is stdout"
21.puts stderr "this is stderr"
通过
fileevent
,以上程序提供了一个非常优雅的重定向办法,但是带程序的作者还附加了一句话。事实上,这段代码是无法正确执行的,因为重定义的
stdout
并没有被创建,而且该
bug
似乎至今没有被修复。
warning: the current distribution has a bug, I have submitted a patch to the author
在
cucumber1.1.1
的
tclsh
中需要将
puts
的内容如同
return
的结果一样写入
text
文本组件中,但考虑到循环打印的情况,又不能仅仅将
puts
当做
return
来对待,从而导致执行代码的中止。我的解决办法依然是使用
rename
,在
puts
之前注入代码。
1.con eval {
2. rename puts _puts
3. proc puts {args} {
4. putsstdout $args
5. }
6.}
7.interp alias con putsstdout {} putsstdout
8.proc putsstdout {msg} {
9. .console insert end "$msg\n"
10. .console see end
11.}
模拟
tclsh
的过程是发生在名为
con
的子解析器里的,需要使用
alias
将子解析器中的数据交由主解析器中的函数来更新
.console
中的显示。以上代码中的第
4
行便是重定向的关键所在,当然我们还可以将数据以传统形式输出到
stdout
中,这就看具体情况而定了。事实上,这种办法并不算是真正意义上的重定向,但是得到了相同的效果。