逐行执行tcl命令
我有这样一个文件:逐行执行tcl命令,tcl,Tcl,我有这样一个文件: set position {0.50 0.50} set visibility false set text {ID: {entity.id}\n Value: {entity.contour_val}} 我想做一些类似于源代码的事情,但我只想使用一个文件句柄 我当前的尝试如下所示: proc readArray {fileHandle arrayName} { upvar $arrayName arr set cl 0
set position {0.50 0.50}
set visibility false
set text {ID: {entity.id}\n Value: {entity.contour_val}}
我想做一些类似于源代码的事情,但我只想使用一个文件句柄
我当前的尝试如下所示:
proc readArray {fileHandle arrayName} {
upvar $arrayName arr
set cl 0
while {! [eof $fileHandle]} {
set cl [expr "$cl + 1"]
set line [gets $fileHandle]
if [$line eq {}] continue
puts $line
namespace eval ::__esg_priv "
uplevel 1 {*}$line
"
info vars ::__esg_priv::*
foreach varPath [info vars ::__esg_priv::*] {
set varName [string map { ::__esg_priv:: "" } $varPath]
puts "Setting arr($varName) -> [set $varPath]"
set arr($varName) [set $varPath]
}
namespace delete __esg_priv
}
puts "$cl number of lines read"
}
我尝试了许多评估和引用的组合,以代替uplevel。
我的问题是,它要么在有列表的行上失败,要么没有实际设置变量。
如果期望执行的命令是任何有效代码,那么正确的方法是什么
另外一个问题是如何正确地应用错误检查,我还没有尝试过
打电话给
readArray [open "myFile.tcl" r] arr
我想
parray arr
例如:
arr(position) = 0.50 0.50
arr(text) = ID: {entity.id}\n Value: {entity.contour_val}
arr(visibility) = false
顺便说一句:最后一行包含内部{},这应该使它成为字符串变量。我们无意将此作为一条命令。此代码可以工作,但仍存在一些问题:
proc readArray {fileHandle arrayName} {
upvar $arrayName arr
set cl 0
while {! [eof $fileHandle]} {
incr cl ;# !
set line [gets $fileHandle]
if {$line eq {}} continue ;# !
puts $line
namespace eval ::__esg_priv $line ;# !
foreach varPath [info vars ::__esg_priv::*] {
set varName [string map { ::__esg_priv:: "" } $varPath]
puts "Setting arr($varName) -> [set $varPath]"
set arr($varName) [set $varPath]
}
namespace delete __esg_priv
}
puts "$cl number of lines read"
}
我删掉了几行似乎不必要的行,并对一些行做了一些修改
您不需要set cl[expr“$cl+1”]
:incr cl
就可以了
如果[$line eq{}]继续
将失败,因为[…]
是命令替换如果{$line eq{}}继续
(用大括号代替大括号)执行您的操作
除非您在另一个作用域中访问变量,否则不需要uplevel
<代码>名称空间求值::_esg_priv$line将求值指定名称空间中的一行
我没有改变以下内容,但也许你应该:
set varName[string map{:::_esg_priv::”“}$varPath]
按预期工作,但set varName[namespace tail$varPath]
更干净
请注意,如果存在与文件中某个变量同名的全局变量,则不会创建名称空间变量;全局变量将被更新
如果要将文本中的值用作字典,则需要删除\n
或大括号
根据问题标题,您希望逐行评估文件。如果可以取消这一要求,那么可以通过在一次操作中读取整个脚本,然后使用单个名称空间eval
对其进行评估来简化代码
ETA
此解决方案更加健壮,因为它在沙箱中读取脚本(编写将执行任意外部代码的代码时,这是一个好主意),并重新定义(在该沙箱中)set
命令以在数组中创建成员,而不是常规变量
proc readArray {fileHandle arrayName} {
upvar 1 $arrayName arr
set int [interp create -safe]
$int alias set apply {{name value} {
uplevel 1 [list set arr($name) $value]
}}
$int eval [read $fileHandle]
interp delete $int
}
为了更安全地防止与全局变量等的意外交互,请查看Tcllib中的interp
包。它允许您创建一个完全为空的解释器
文档:,,,,,,,,,,感谢所有宝贵的意见和改进。尽管如此,它似乎仍然没有达到我想要的效果。我将尝试编辑该问题以使其成为可能clearer@Ingo:您期望的结果正是我运行代码并打印数组时得到的结果。你得到了什么?很有趣。没有为我定义数组。我会再检查一遍。好的,再次谢谢。看来我破坏了我的环境。我正在主机应用程序中运行,重新启动后,它开始工作。也许是因为打开的文件句柄…@Ingo:好的。关于你关于错误处理的第二个问题,我认为最好是发布一个新问题,因为这是另一回事。