【问题标题】:How to suppress a proc's return value in tcl prompt如何在 tcl 提示符中抑制 proc 的返回值
【发布时间】:2013-04-02 21:44:20
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我认为没有办法做到这一点。为什么要禁用它?
  • 为什么这很重要?您是否知道这是交互式 shell 的一项功能,而不是您在运行基于文件的脚本时会注意到的功能?
  • 这就是 tclsh 的工作原理。更改 C 源代码,构建没有此行为的 tclsh,并将其作为替代 tclsh 提供给您的用户。
  • 一个变色龙问题。你刚刚取消了大部分答案的资格。
  • set 命令的结果是新值。 set a [set b [set c 34]] 将 a、b 和 c 设置为 34。通过一些技巧 (trace),它可以返回与 a 的结果不同的值

标签: tcl return-value


【解决方案1】:

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

很多命令会产生空结果:

if 1 {}
subst ""
format ""

不过,最短的大概是:

list

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

a;list

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

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

我发现最有用的命令是string lengthllengthdict 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 自己的内置钩子的更优雅的方法是使用execution trace 来检测命令是否已被调用(为简洁起见,我将在这里仅显示非事件循环版本)。这样做的另一个优点是它很容易扩展到抑制多个命令的输出:只需将跟踪添加到每个命令。

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 ""
    }
}

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

【讨论】:

  • 如果需要,您也可以编写自己的 read-eval-print-loop(不包括打印部分)。这比通常合理的工作要多。
  • 根据我的更新,我必须默默地传递返回值。因此,即使我在原始过程中编写了一个包装器,它也达不到目的。
  • @abasu 如此大幅度地改变人们的要求并不好(问另一个问题!)但我希望我的扩展答案能解决如何做到这一点。请注意,您必须使用您自己的交互循环来完成这种技巧。 (执行跟踪不能改变命令的输出,只能抛出错误,你可能不想这样做!)
  • 我知道最初的问题描述不充分。实际上我认为这将是简单的设置一些详细程度。在第一批帖子之后,我理解了错误并更新了描述。不管怎样,谢谢你的帖子。这对我来说似乎是最好/唯一的方法(除非我更改 c 代码并构建另一个 tclsh :))
【解决方案2】:

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

proc void {} {}

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

【讨论】:

    【解决方案3】:

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

    proc a {} {
        puts "hello"
        if { [info exist tcl_interactive] } {
            return {};
        } else {
            return 34;
        }
    } 
    

    【讨论】:

    • 你不应该只检查变量是否存在。 tcl_interactive 在他的情况下总是1。也可以考虑使用info level
    • 根据我的更新,我需要以静默方式传递返回值。所以即使是交互模式,我也需要一个返回值,我不想要的是 tcl 提示回显该值
    • @abasu:好的,我认为如果您以非交互方式使用它,您只需要返回值。所以使用 tcl 提示符是你标准工作程序的一部分...
    • @Kuhn:我已经通过在 shell(顶部带有 #!/usr/bin/tclsh)中运行它并将其作为源命令的一部分运行来检查这一点。为此,它起作用了。
    猜你喜欢
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    相关资源
    最近更新 更多