Tcl:这个过程如何 return 一个值?

Tcl: how does this proc return a value?

我正在修改下面的代码,但我不知道它是如何工作的-欢迎指教。问题是其中有一个 proc (cygwin_prefix) 是为了创建一个命令,通过

  1. 不修改文件名,或
  2. 在文件名前添加一个字符串

问题是 proc returns 什么都没有,但脚本神奇地仍然有效。如何?具体来说,set command [cygwin_prefix filter_g] 行实际上是如何设法正确设置 command?

对于后台,脚本只是执行 filter_g < foo.txt > foo.txt.temp。然而,从历史上看(这似乎不再是这种情况)这在 Cygwin 上不起作用,所以它改为 运行 /usr/bin/env tclsh filter_g < foo.txt > foo.txt.temp。 Linux (Tcl 8.5) 和 Cygwin (Tcl 8.6) 上显示的脚本 'works'。

谢谢。


#!/usr/bin/env tclsh

proc cygwin_prefix { file } {
    global cygwin
    if {$cygwin} {
        set status [catch { set fpath [eval exec which $file] } result ]
        if { $status != 0 } {
            puts "which error: '$result'"
            exit 1
        }
        set file "/usr/bin/env tclsh $fpath"
    }
    set file
}

set cygwin 1
set filein foo.txt
set command [cygwin_prefix filter_g]
set command "$command < $filein > $filein.temp"
set status [catch { eval exec $command } result ]
if { $status != 0 } {
    puts "filter error: '$result'"
    exit 1
}
exit 0

不需要exec使用eval。将命令构建为列表将保护您免受例如包含 space 的路径项的影响。这是一个快速重写来演示:

proc cygwin_prefix { file } {
    if {$::cygwin} {
        set status [catch { set fpath [exec which $file] } result]
        if { $status != 0 } {
            error "which error: '$result'"
        }
        set file [list /usr/bin/env tclsh $fpath]
    }
    return $file
}

set cygwin 1
set filein foo.txt
set command [cygwin_prefix filter_g]
lappend command "<" $filein ">" $filein.temp

set status [catch { exec {*}$command } result]
if { $status != 0 } {
    error "filter error: '$result'"
}

这使用 {*} 将列表分解为单个单词以传递给 exec

你的问题的关键是two-fold。

  1. 如果过程没有以 return(当然是 error)结束,则该过程的结果是该过程中执行的最后一条命令的结果body。

    (如果没有执行任何命令,则为空字符串。在这种情况下不适用。)

    这对于像只包装命令的过程这样的东西很有用:

    proc randomPick {list} {
        lindex $list [expr { int(rand() * [llength $list]) }]
    }
    

    是的,您可以添加 return […],但这只会让这么短的内容变得混乱。

  2. set命令,带一个参数,读取命名变量,并产生 var 中的值作为其结果。

    很久以前(现在大约 30 年),这是读取所有变量的方式。对我们来说幸运的是,添加了 $… 语法,这在 99.99% 的情况下都更加方便。唯一有时有意义的地方是计算变量名,但大多数时候甚至还有更好的选择。

您在过程末尾使用 set file 而不是 return $file 的形式流行了一段时间,因为它产生了 稍微 更短的字节码。通过一个 unreachable 操作码。字节码的差异现在消失了。也没有性能差异,而且从来没有(特别是与启动子进程并通常进行大量系统调用的 exec 的权重相比!)