dut1Loop1Net = [::ip::contract [::ip::prefix 1.1.1.1/24]]/24
set in [open file1.txt r]
set line [gets $in]
if {[string trim [string range $line1 0 0]] != "#"} {
set devicePort [string trim [lindex $line1 0]]
set mark [expr [string first "=" $line1] + 1]
set val [string trim [string range $line1 $mark end]]
global [set t $devicePort]
set [set t $devicePort] $val
}
close $in
我的输出为
% set dut1Loop1Net
[::ip::contract [::ip::prefix 1.1.1.1/24]]/24
这里我没有评估字符串。
我希望输出为1.1.1.0/24
。因为TCL不在此处评估代码,所以它像字符串一样打印。
我很有兴趣知道TCL如何存储数据以及它将以何种形式检索数据。
答案 0 :(得分:4)
短篇小说:
<强> Everything is a string 强>
长篇大论
Tcl将数据存储在上次使用的数据类型中,仅在nessecary时计算字符串表示,使用copy on write,简单的refcount内存管理。
答案如何评估它是eval
或subst
。在您的情况下可能是subst
。
如果您的配置文件如下所示:
# This is a comment
variable = value
othervar = [doStuff]
你可以使用一些技巧让Tcl为你解析它:
rename ::unknown ::_confp_unknown_orig
proc unknown args {
if {[llength $args] == 3 && [lindex $args 1] eq "="} {
# varname = value
uplevel 1 [list set [lindex $args 0] [lindex $args 2]
return [lindex $args 2]
}
# otherwise fallback to the original unknown
uplevel 1 [linsert $args 0 ::_confp_unknown_orig]
# if you are on 8.6, replace the line above with
# tailcall ::_confp_unknown_orig {*}$args
}
# Now just source the file:
source file1.txt
# cleanup - if you like
rename ::unknown {}
rename ::_confp_unknown_orig ::unknown
另一种方法是使用安全的interp,但在这种情况下使用你的主interp看起来很好。
答案 1 :(得分:0)
问题是您在val
内存储的代码永远不会被执行。
您可以使用$val
访问它,但这样您就可以获得代码本身,而不是执行代码的结果。
要解决此问题,您必须确保[::ip::contract [::ip::prefix 1.1.1.1/24]]/24
已执行,并且您可以通过替换此行来实现此目的
set val [string trim [string range $line1 $mark end]]
这一个
eval "set val [string trim [string range $line1 $mark end]]"
为什么呢?这是我的简单解释:
"..."
部分,因此它会在其中执行替换string range $line1 $mark end
命令string trim ...
命令因此,当替换完成且eval
命令准备好运行时,它就像你的行一样
eval {set val [::ip::contract [::ip::prefix 1.1.1.1/24]]/24}
现在执行eval
命令,它会递归调用解释器,因此字符串set val [::ip::contract [::ip::prefix 1.1.1.1/24]]/24
进入另一个替换阶段,最终运行你想要的并放置字符串1.1.1/24
到变量val
。
我希望这会有所帮助。