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

TCL/Expect equivalent of Bash $@ or how to pass arguments to spawned process in TCL/Expect

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

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

在 TCL/Expect 中是否有类似的东西?

编辑: 到目前为止,我已经有了这个 hack(评论中有 Bash 等价物),这似乎是有效的。有人可以解释一下 lshift 程序吗?

# 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=""
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 的 "list expansion" 语法(Tcl's 12 rules of syntax 的规则 5)。它在当前命令中将列表拆分为其元素。

如果$argvfoo 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 jackman 的回答对于较旧的 TCL(即 8.5 之前的版本),尤其是较旧的 Unicies 运行 Expect scipts 是不够的。我去搜索并发现了一个说明 "lassign" 功能在 8.5 之前的 TCL 中不可用:(http://wiki.tcl.tk/1530 ,在 "In Tcl prior to 8.5, foreach was used to achieve the functionality of lassign:" 部分)。

在同一页面上,在标题 "Example: Perl-ish shift" 下,有一个语句 "On the other hand, Hemang Lavana observes that TclXers already have lvarpop ::argv, an exact synonym for 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
}

在我的测试中,这适用于零到几乎无限数量的 space-separated args。对于像我这样的 TCL-challenged 来说,这是天赐之物。