tclsh
中的交互式 shell 代码wish
将打印任何非空结果。为了不打印任何内容,您必须让“行”上的最后一个命令产生一个空结果。但是使用哪个命令?
许多命令会产生空结果:
if 1 {}
subst ""
format ""
但是,最短的可能是:
list
因此,您可以编写如下代码:
a;list
当然,只有当您的命令实际上产生了您不想看到的大结果时,这才真正变得有用。在这些情况下,我经常发现使用测量结果大小的东西最有用,例如:
set tmp [something_which_produces a_gigantic result]; string length $tmp
我找到的最有用的命令是string length
,llength
和dict size
.
如果您绝对不能打印命令的结果,则必须编写自己的交互式循环。有两种方法可以做到这一点,具体取决于您是否在事件循环中运行:
没有事件循环
这个简单的版本只是检查命令名称是否在用户键入的内容中。否则随意丢弃结果可能不是一个好主意!
set accum ""
while {[gets stdin line] >= 0} {
append accum $line "\n"
if {[info complete $accum]} {
if {[catch $accum msg]} {
puts stderr $msg
} elseif {$msg ne "" && ![string match *TheSpecialCommand* $accum]} {
puts $msg
}
set accum ""
}
}
使用事件循环
这只是处理阻塞 IO 的情况;当输入来自熟终端(即默认)时,这是正确的
fileevent stdin readable handleInput
set accum ""
proc handleInput {} {
global accum
if {[gets stdin line] < 0} {
exit; # Or whatever
}
append accum $line "\n"
if {[info complete $accum]} {
if {[catch {uplevel "#0" $accum} msg]} {
puts stderr $msg
} elseif {$msg ne "" && ![string match *TheSpecialCommand* $accum]} {
puts $msg
}
set accum ""
}
}
vwait forever; # Assuming you're not in wish or have some other event loop...
如何检测正在执行的命令
上面的代码![string match *TheSpecialCommand* $accum]
用来决定是否丢弃命令结果,但这很丑陋。利用 Tcl 自己的内置钩子的更优雅的方法是使用执行跟踪来检测命令是否已被调用(为简洁起见,我将在此处仅显示非事件循环版本)。这样做的另一个优点是它很容易扩展到抑制多个命令的输出:只需将跟踪添加到每个命令。
trace add execution TheSpecialCommand enter SuppressOutput
proc SuppressOutput args {
# Important; do not suppress when it is called inside another command
if {[info level] == 1} {
set ::SuppressTheOutput 1
}
}
# Mostly very similar from here on
set accum ""
while {[gets stdin line] >= 0} {
append accum $line "\n"
if {[info complete $accum]} {
set SuppressTheOutput 0; # <<<<<< Note this!
if {[catch $accum msg]} {
puts stderr $msg
} elseif {$msg ne "" && !$SuppressTheOutput} { # <<<<<< Note this!
puts $msg
}
set accum ""
}
}
需要明确的是,我永远不会在自己的代码中这样做!如果重要的话,我会手动抑制输出。