TCL/Expect 相当于 Bash $@ 或如何将参数传递给 TCL/Expect 中的衍生进程
Posted
技术标签:
【中文标题】TCL/Expect 相当于 Bash $@ 或如何将参数传递给 TCL/Expect 中的衍生进程【英文标题】:TCL/Expect equivalent of Bash $@ or how to pass arguments to spawned process in TCL/Expect 【发布时间】:2015-03-19 01:44:10 【问题描述】:如果有人想从 Bash 调用外部程序(作为 Bash 参数传递)并传递命令行选项(也作为 Bash 参数传递),那么解决方案非常简单:
TCL_SCRIPT="$1"
shift
TCL_SCRIPT_ARGUMENTS="$@"
expect -f "$TCL_SCRIPT" "$TCL_SCRIPT_ARGUMENTS" 2>&1
在 TCL/Expect 中是否有类似的可能?
编辑: 到目前为止,我已经有了这个 hack(在 cmets 中有 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="$1"
set script [lindex $argv 0]
# BASH: shift
lshift argv
# BASH: TCL_SCRIPT_ARGUMENTS="$@"
set arguments $argv
【问题讨论】:
该脚本,如所写,不适用于带空格的参数。只是为了记录。您不会将$@
存储在变量中,您只需在需要的地方使用它。除此之外,我不确定我是否理解这个问题。您是否在询问如何通过expect
将参数传递给命令spawn
ed?你的expect
脚本是什么样的?
如果你使用的是 tcl8.6,你可以使用exec *$::argv 2>@1
。否则,总是有eval exec $::argv 2>@1
。
我的意思是,如果你有一个带空格的参数,当你把它塞进一个字符串时,你将失去使$@
安全的单词扩展行为。请尝试以下操作以了解我的意思。 c() printf 'argc: %s\n' "$#"; printf '$@: %s\n' "$@"; TCL_SCRIPT_ARGUMENTS="$@"; printf 'TCL_SCRIPT_ARGUMENTS: %s\n' "$TCL_SCRIPT_ARGUMENTS"; ; c foo 'bar baz' quux
(将set -x
添加到该函数的开头也可以更清楚地看到它。)
printf
反复使用该格式来消耗其所有输入。因此,当您说printf '%s\n' a b c
时,它需要使用%s\n
格式三次才能使用它。大多数命令都不是这样工作的。
@WakanTanka *$var
是 tcl
等价于 "$@"
:它将扩展列表,以便每个列表元素都是正确引用的参数。所以,假设我们有set lst item1 "item 2" item3
,MyProc *$lst
相当于MyProc item1 item 2 item3
【参考方案1】:
从字面上翻译你的例子
set program [lindex $argv 0]
set arguments [lrange $argv 1 end]
spawn $program *$arguments
*
是 Tcl 的“列表扩展”语法(Tcl's 12 rules of syntax 的规则 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 进行编码:
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
【讨论】:
感谢您的回复。您能解释一下*
在这种情况下的含义吗?【参考方案2】:
我发现@glenn jackman 的答案对于较旧的 TCL,即 8.5 之前的版本,特别是对于运行 Expect scipts 的较旧的 Unicies 来说是不够的。我去搜了一下,发现一个说明是8.5之前的TCL中没有“lassign”功能:(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 挑战者来说,这是天赐之物。
【讨论】:
以上是关于TCL/Expect 相当于 Bash $@ 或如何将参数传递给 TCL/Expect 中的衍生进程的主要内容,如果未能解决你的问题,请参考以下文章
sql 示例:如果行存在,则如何更新行或如果行不存在则插入行
Tensorflow / Keras:规范化训练/测试/实时数据或如何处理现实?