Tcl:这个过程如何 return 一个值?
Tcl: how does this proc return a value?
我正在修改下面的代码,但我不知道它是如何工作的-欢迎指教。问题是其中有一个 proc (cygwin_prefix
) 是为了创建一个命令,通过
- 不修改文件名,或
- 在文件名前添加一个字符串
问题是 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。
如果过程没有以 return
(当然是 error
)结束,则该过程的结果是该过程中执行的最后一条命令的结果body。
(如果没有执行任何命令,则为空字符串。在这种情况下不适用。)
这对于像只包装命令的过程这样的东西很有用:
proc randomPick {list} {
lindex $list [expr { int(rand() * [llength $list]) }]
}
是的,您可以添加 return […]
,但这只会让这么短的内容变得混乱。
set
命令,带一个参数,读取命名变量,并产生 var 中的值作为其结果。
很久以前(现在大约 30 年),这是读取所有变量的方式。对我们来说幸运的是,添加了 $…
语法,这在 99.99% 的情况下都更加方便。唯一有时有意义的地方是计算变量名,但大多数时候甚至还有更好的选择。
您在过程末尾使用 set file
而不是 return $file
的形式流行了一段时间,因为它产生了 稍微 更短的字节码。通过一个 unreachable 操作码。字节码的差异现在消失了。也没有性能差异,而且从来没有(特别是与启动子进程并通常进行大量系统调用的 exec
的权重相比!)
我正在修改下面的代码,但我不知道它是如何工作的-欢迎指教。问题是其中有一个 proc (cygwin_prefix
) 是为了创建一个命令,通过
- 不修改文件名,或
- 在文件名前添加一个字符串
问题是 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。
如果过程没有以
return
(当然是error
)结束,则该过程的结果是该过程中执行的最后一条命令的结果body。(如果没有执行任何命令,则为空字符串。在这种情况下不适用。)
这对于像只包装命令的过程这样的东西很有用:
proc randomPick {list} { lindex $list [expr { int(rand() * [llength $list]) }] }
是的,您可以添加
return […]
,但这只会让这么短的内容变得混乱。set
命令,带一个参数,读取命名变量,并产生 var 中的值作为其结果。很久以前(现在大约 30 年),这是读取所有变量的方式。对我们来说幸运的是,添加了
$…
语法,这在 99.99% 的情况下都更加方便。唯一有时有意义的地方是计算变量名,但大多数时候甚至还有更好的选择。
您在过程末尾使用 set file
而不是 return $file
的形式流行了一段时间,因为它产生了 稍微 更短的字节码。通过一个 unreachable 操作码。字节码的差异现在消失了。也没有性能差异,而且从来没有(特别是与启动子进程并通常进行大量系统调用的 exec
的权重相比!)