使用一个proc时,我的脚本运行正常(检索sftp提示符)。但是当我尝试在proc内部使用proc时,脚本会卡住,我不知道为什么。
请不要重构代码,这不是重点,我需要了解这里的问题。
工作代码:
proc sftp_connect {} {
set times 0;
set connection_retry 2
set timeout 1;
while { $times < $connection_retry } {
spawn sftp ${SFTP_USER}@${SFTP_SERVER}
expect {
timeout { puts "Connection timeout"; exit 1}
default {exit 2}
"*assword:*" {
send "${SFTP_PASSWORD}\n";
expect {
"sftp>" { puts "Connected"; set times [ expr $times+1]; exp_continue}
}
}
}
}
send "quit\r";
}
sftp_connect
调试输出:
expect: does "\r\nsftp> " (spawn_id exp5) match glob pattern "sftp>"? yes
但是在将发送密码移动到单独的proc之后,期望不再检索sftp提示符(“sftp&gt;”):
proc sftp_send_password {} {
send "${SFTP_PASSWORD}\n";
expect {
"sftp>" { puts "Connected"; set times [ expr $times+1]; exp_continue}
}
}
proc sftp_connect {} {
set times 0;
set connection_retry 2
set timeout 1;
while { $times < $connection_retry } {
spawn sftp ${SFTP_USER}@${SFTP_SERVER}
expect {
timeout { puts "Connection timeout"; exit 1}
default {exit 2}
"*assword:*" { sftp_send_password }
}
}
send "quit\r";
}
sftp_connect
调试输出:
expect: does "" (spawn_id exp0) match glob pattern "sftp>"? yes
答案 0 :(得分:2)
我没有方便的“探索期待”副本,但我认为你正在遇到一个变量范围问题。 spawn
无形地设置名为spawn_id
的变量。在proc中调用spawn时,该变量的范围仅限于该proc。将其声明为全局:
proc sftp_connect {} {
global spawn_id
# ... rest is the same
}
我认为你不必在sftp_send_password
中做同样的事情,因为期望有一个比Tcl更宽容的范围方案(如果期望找不到局部变量,请查看全局命名空间)。
由于相同的变量范围问题,您的sftp_send_password
proc不会影响times
中的sftp_connect
变量。我推荐
proc sftp_send_password {times_var} {
upvar 1 $times_var times ;# link this var to that in the caller
send "${SFTP_PASSWORD}\n";
expect {
"sftp>" { puts "Connected"; incr times; exp_continue}
}
# note use of `incr` instead of `expr`
}
然后sftp_connect
proc发送times
变量名称:
sftp_send_password times
答案 1 :(得分:1)
以下内容来自expect
的手册页:
Expect对范围界定采取相当自由的观点。特别是,将首先从特定于Expect程序的命令读取的变量 本地范围,如果没有找到,则在全局范围内。例如,这消除了在您编写的每个过程中放置
global timeout
的需要 使用期望。另一方面,写入的变量始终在本地范围内(除非已发出global
命令)。 最常见的 这个问题导致的是在程序中执行spawn
。在程序之外,spawn_id
不再存在,因此产生的进程不再存在 因为范围界定而无法访问。在此类程序中添加global spawn_id
。