检查变量是否被 Tcl 重新定义

Check if a variable is redefined by Tcl

提问人:JoshTitle 提问时间:10/14/2023 最后编辑:Donal FellowsJoshTitle 更新时间:10/17/2023 访问量:84

问:

在我的脚本中,我将获取其他所有者的 TCL 脚本。

我尝试检查所有变量是否在他们的 tcl 脚本文件中重新定义,在这里我尝试在我的脚本中:

proc trace_var {args} {
   set frame [info frame];
   set frame_info [info frame [expr {$frame -2}]];
   puts "$args set in $frame_info"
}
trace add execution set leave trace_var
#source other owner script file
source #FILE1_FROM_OTHERS
#file content:
set a 123
set b 123456 ..... 
#Just example, I don't know the all var name, in fact. 
source #FILE2_FROM_OTHERS
set xxx 456;
set yyy 999;
set a 2; #<- want to catch such case
#Do my remain script body

更新: #File1、#File2、#FileN 有超过 3000+ 个变量。 我不知道如何通过跟踪变量来使用。我想抓住的情况是,如果有任何变量在 #FILE1、#FILE2、... #FILEN 中重新定义

TCL 跟踪 var 过程

评论

0赞 Donal Fellows 10/15/2023
为什么不改用变量呢?除了...traceset
0赞 JoshTitle 10/15/2023
变量来自其他人的文件,文件中有超过 3000+ 个变量,我不知道变量名称。

答:

2赞 Cyan Ogilvie 10/15/2023 #1

除了使用命令之外,还有很多方法可以创建或更改变量,尝试像这样进行监视的方法实在太多了。仅举一些例子:set

lassign $foo a b     ;# variables a and b set / updated
dict set foo bar baz ;# variable foo set or updated
foreach element $list {}   ;# variable element set
dict with foo {}     ;# any keys in $foo become variables

这不仅限于 Tcl 内置命令,例如,我的命令与上述大多数示例等效,因此,除非您阻止由您采购的脚本定义新命令,否则甚至不可能通过跟踪所有可能影响变量的已知命令来跟踪它。json

我不确定您的用例的细节,但如果它只是全局变量,我可能会尝试这样的事情:

proc var_changed {v n1 n2 op} {
    puts "variable $v $op"
}

set start_vars [info vars]
foreach v $start_vars {
    trace add variable $v {write unset} [list var_changed $v]
}

source $other_file

foreach v [info vars] {
    if {$v ni $start_vars} {
        puts "New var defined: $v"
    }
}

在执行跟踪处理程序时,将禁止对触发该处理程序的变量进行其他跟踪。

此示例不处理数组变量或未设置然后重新添加的变量可能发生的所有情况。可以将这种技术扩展到命名空间中的变量,但它开始让人感到脆弱和沉重。如果你的用例真的是关于包含未知内容的源脚本的副作用,那么我建议你宁愿在子解释器中获取脚本(如果你不信任脚本的源,则是一个安全的子解释器),也许是这样的:

set child [interp create -safe]
$child eval [list set foo $foo]    ;# Copy the state of selected variables
$child eval [list set bar $bar]    ;# to the child interp

$child eval [list source $other_file]

# Retrieve the state of vars in the child after sourcing $other_file if needed:
puts "foo in child: [$child eval [list set foo]]"

# Clean up
interp delete $child

评论

0赞 JoshTitle 10/16/2023
它有效,但是我能知道第一个变量在哪个文件、行中定义吗?甚至我不知道 var 名称
0赞 Cyan Ogilvie 10/16/2023
使用任何一种技术(查找所有当前变量并跟踪它们/在子接口中获取脚本),都可以知道哪个脚本首先定义了它们(通过在每个脚本运行后比较定义的变量集),但不能知道这些脚本中的行号。如果你真的非常需要它(以证明执行成本的大幅增加是合理的),那么你可以用离开步跟踪来做到这一点 - 这样你的处理程序就会在每个命令执行后运行,然后它会比较变量的当前快照以找到任何新的变量,并检查该行的调用帧堆栈。