3

我在 TCL 中相对较新,在 TCL 提示符下,当我们调用具有某些返回值的 proc 时,proc 的返回值由 tcl 回显。有没有办法阻止它(不影响puts或类似功能)作为例子

bash$ tclsh
% proc a {} { puts  "hello"; return 34; }
% a
hello
34
%

现在我如何抑制 34 出现在屏幕上?任何帮助表示赞赏。

更新:实际上 proc 是另一个工具的一部分,之前它没有任何返回值,但现在它可以有条件地返回一个值。它可以从脚本中调用,不会有任何问题(正如 Bryan 指出的那样)。并且可以从交互式提示中调用它,然后在所有必要的输出之后,不必要地打印返回值。所以 1) 我没有更改用户的 tclshrc 2) 现有脚本应该继续工作的设施。每次调用 proc 时,在所有必要的输出之后,都会打印一个数字,这似乎很奇怪。对于用户来说,这是一个不必要的信息,除非他已经抓住了价值并想做某事。所以我希望将价值传递给用户,但没有打印到提示/用户界面(希望我很清楚)

4

3 回答 3

3

tclsh中的交互式 shell 代码wish将打印任何非空结果。为了不打印任何内容,您必须让“行”上的最后一个命令产生一个空结果。但是使用哪个命令?

许多命令会产生空结果:

if 1 {}
subst ""
format ""

但是,最短的可能是:

list

因此,您可以编写如下代码:

a;list

当然,只有当您的命令实际上产生了您不想看到的大结果时,这才真正变得有用。在这些情况下,我经常发现使用测量结果大小的东西最有用,例如:

set tmp [something_which_produces a_gigantic result]; string length $tmp

我找到的最有用的命令是string length,llengthdict 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 ""
    }
}

需要明确的是,我永远不会在自己的代码中这样做!如果重要的话,我会手动抑制输出。

于 2013-04-01T13:43:31.650 回答
1

您可以在 .tclshrc 中创建一个空程序...

proc void {} {}

...当您不需要返回值时,以 . 结束该行;void

于 2013-04-01T12:59:32.387 回答
-1

使用tcl_interactive变量来启用值的返回,虽然我不确定这在哪里有用......

proc a {} {
    puts "hello"
    if { [info exist tcl_interactive] } {
        return {};
    } else {
        return 34;
    }
} 
于 2013-04-02T13:44:20.943 回答