如何向tcl脚本传递字符串并正确解释它

如何向tcl脚本传递字符串并正确解释它,tcl,Tcl,我正在尝试修改一个tcl脚本,该脚本使用xilinx的xsct工具将位文件推送到FPGA上。下面是它的样子: connect hw_server TCP:127.0.0.1:3122 targets -set -filter {jtag_cable_name =~ "Digilent JTAG-HS2 21xxx" && name =~ "xc7*"} fpga [lindex $argv 0] after 100 targets -set -filter {jtag_cable

我正在尝试修改一个tcl脚本,该脚本使用xilinx的xsct工具将位文件推送到FPGA上。下面是它的样子:

connect hw_server TCP:127.0.0.1:3122
targets -set -filter {jtag_cable_name =~ "Digilent JTAG-HS2 21xxx" && name =~ "xc7*"}
fpga [lindex $argv 0]
after 100
targets -set -filter {jtag_cable_name =~ "Digilent JTAG-HS2 21xxx" && name =~ "Micro*"}
loadhw system.hdf
stop
dow [lindex $argv 1]
con -block
load_fpga.tcl "Digilent JTAG-HS2 21xxx" my_bitfile.bit my_elf.elf
现在我有了多个FPGA,我想把jtag_电缆名称作为一个参数。我试过了,但没有用:

connect hw_server TCP:127.0.0.1:3121
targets -set -filter {jtag_cable_name =~ [eval [lindex[$argv 0]] && name =~ "xc7*"}
fpga [lindex $argv 1]
after 100
targets -set -filter {jtag_cable_name =~ [eval [lindex[$argv 0]] && name =~ "Micro*"}
loadhw system.hdf
stop
dow [lindex $argv 2]
con -block
对.tcl脚本的调用如下所示:

connect hw_server TCP:127.0.0.1:3122
targets -set -filter {jtag_cable_name =~ "Digilent JTAG-HS2 21xxx" && name =~ "xc7*"}
fpga [lindex $argv 0]
after 100
targets -set -filter {jtag_cable_name =~ "Digilent JTAG-HS2 21xxx" && name =~ "Micro*"}
loadhw system.hdf
stop
dow [lindex $argv 1]
con -block
load_fpga.tcl "Digilent JTAG-HS2 21xxx" my_bitfile.bit my_elf.elf

如何正确地传递字符串并像原始字符串一样将其保留在引号中?

您没有意识到的是,在tcl中,
{Hello World}
是一个字符串

如果您熟悉Perl或Ruby等语言,那么您就会熟悉文本字符串和插值字符串的概念。在tcl中,字符串有三种语法:

  • 任何不包含空格(空格、制表符、换行符)的内容都是字符串。此外,空格可能会被转义。转义空白不被视为空白。以下是字符串:

    hello
    hello\ world
    
  • 任何按
    分组的字符串都是插值字符串。插值字符串可能包含变量或命令,这些变量或命令将被计算和替换。以下字符串都表示“hello world”:

  • {}
    分组的任何内容都是文字字符串。文字字符串不插值。也就是说,不计算变量或命令。以下是文字字符串:

    {hello world} ;# hello world
    {$x world}    ;# $x world
    

  • 为了得到你想要的东西,你可以做两件事

  • {}
    替换为
    。这将使文本字符串成为插值字符串:

    "jtag_cable_name =~ [eval [lindex[$argv 0]] && name =~ \"xc7*\""
    
    请注意如何在字符串中转义

  • 使用
    subst
    命令。
    substict
    命令对字符串执行替换:

    [subst {jtag_cable_name =~ [eval [lindex[$argv 0]] && name =~ "xc7*"}]
    
    这样做的一个小优点是您不需要逃避
    。请阅读
    subst
    的手册页面。它非常灵活,允许您选择要替换的内容类型。例如,它允许您仅计算命令,而不计算
    $
    语法

  • 您可能想要:

    set jtag_cable_name [lindex $argv 0]
    # ...
    targets -set -filter [format {jtag_cable_name =~ "%s" && name =~ "xc7*"} $jtag_cable_name]
    
    可以按如下方式分配所有命令行参数:

    lassign $argv  jtag_cable_name  bit_filename  elf_filename
    

    请注意,
    {}
    语法始终是一个字符串。例如,您可能认为
    if
    的语法是
    if expression code else code
    ,但实际上是
    if string else string
    Tcl中的每个值都是字符串(嗯,至少可以序列化为字符串;内置类型都可以可靠地转换为字符串并透明地返回,这样我们就可以在不考虑性能的情况下安全地假装它们都只是字符串)。每个命令的每个字都是Tcl值,即使它看起来像一块代码,并且包括命令本身的名称。(命令和变量不是字符串,而是由字符串命名,并由/包含字符串实现。)这里的
    eval
    的目的是什么?我自己会使用
    格式
    将参数注入字符串中。@glennjackman来自OP的代码。我试图使我的答案包含修复问题所需的最小更改,否则答案会更长。正如您所见,即使更改很少,我的答案也会很长g无论如何,因为我也希望尽可能清楚地解释修复方法,所以您至少应该纠正错误:
    [eval[lindex[$argv 0]]
    您应该在@slebetman answer上找到答案。但是,您不需要这一点:
    [eval[lindex[$argv 0]]
    。这应该是
    [lindex$argv 0]
    。我猜,
    eval
    是您试图将文字再次转换为插值字符串以提取文字的人工制品。从语法上来说,您的
    [eval…]
    也不正确。在
    lindex
    和它的第一个arg之间缺少空格!现在我仔细看:
    [$argv 0]
    首先是错误的。