逐行执行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:好的。关于你关于错误处理的第二个问题,我认为最好是发布一个新问题,因为这是另一回事。