TCL/Expect相当于Bash $@,或者如何将参数传递给TCL/Expect中的生成进程



如果有人想从Bash调用外部程序(作为Bash参数传递)并向其传递命令行选项(也作为Bash参数传递),解决方案非常简单:

TCL_SCRIPT="$1"
shift
TCL_SCRIPT_ARGUMENTS="$@"
expect -f "$TCL_SCRIPT" "$TCL_SCRIPT_ARGUMENTS" 2>&1

在TCL/Expect中可能类似的事情吗?

编辑:到目前为止,我已经有了这个黑客(评论中有 Bash 等效项),它似乎正在工作。有人可以解释一下移位程序吗?

# http://wiki.tcl.tk/918#pagetocc7993a2b
proc lshift {inputlist} {
  upvar $inputlist argv
  set arg  [lindex $argv 0]
  #set argv [lrange $argv 1 end] ;# below is much faster - lreplace can make use of unshared Tcl_Obj to avoid alloc'ing the result
  set argv [lreplace $argv[set argv {}] 0 0]
  return $arg
}
# BASH: TCL_SCRIPT="$1"
set script [lindex $argv 0]
# BASH: shift
lshift argv
# BASH: TCL_SCRIPT_ARGUMENTS="$@"
set arguments $argv

从字面上翻译您的示例

set program [lindex $argv 0]
set arguments [lrange $argv 1 end]
spawn $program {*}$arguments

{*}是Tcl的"列表扩展"语法(Tcl的12条语法规则中的第5条)。它将列表拆分为当前命令中的元素。

如果$argv foo bar baz ,则

spawn [lindex $argv 0] [lrange $argv 1 end]

将使用 1 个参数调用foo"bar baz"

spawn [lindex $argv 0] {*}[lrange $argv 1 end]

将使用 2 个参数调用foo"bar""baz"


切线地,我会像这样编写您的lshift过程:

proc lshift {varname} {      
    upvar 1 $varname var
    set var [lassign $var first]
    return $first
}

然后:

expect1.6> set argv {foo bar baz}
foo bar baz
expect1.7> set script [lshift argv]
foo
expect1.8> set script
foo
expect1.9> set argv
bar baz

我发现杰克曼@glenn答案对于较旧的TCL(即8.5之前的版本)是不够的,尤其是对于运行Expectscipts的旧Unicies也是如此。我去搜索并发现了一个注释,说明"lassign"功能在 8.5 之前的 TCL 中不可用:(http://wiki.tcl.tk/1530 ,在"在 8.5 之前的 Tcl 中,foreach 用于实现 lassign:" 一节)。

在同一页上,在标题"示例:Perl-ish shift"下,有一句话说"另一方面,Hemang Lavana观察到TclXers已经有了lvarpop ::argv,这是shift的确切同义词。重定向到"lvarpop"的此页面:http://wiki.tcl.tk/1965

该页末尾的代码是简化版本,为方便起见,此处转载:

proc lvarpop {upVar {index 0}} {
    upvar 1 $upVar list
    if {![info exists list]} { return "-1" }
    set top [lindex $list $index]
    set list [lreplace $list $index $index]
    return $top
}

在我的测试中,这适用于零到几乎无限数量的空间分隔参数。 对于像我这样TCL挑战者来说,这是天赐之物。

最新更新