为什么我的 Expect 脚本只回显命令未运行?



我正在尝试自动化一些ssh过程。我有我的预期代码。但是我的预期代码仅回显/打印出命令。它实际上并不运行命令。

#!/usr/bin/expect -f
set timeout 10
set usrnm "aaaaaa"
set pwd "pppppp"
set addr1 "xxx.cloud.xxx.com -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
set addr2 "xxx.xxxx.xxxx.com"
spawn ssh $usrnm@$addr1
expect {
"(yes/no)?" {send "yesr";exp_continue}
"password: " {send  "$pwdr"}
}

expect "*#"
send "ssh $usrnm@$addr2r"
expect {
"(yes/no)?" {send "yesr";exp_continue}
"password:" {send  "$pwdr"}
}
expect "*#"
send "cd /tmp/myself/folderr"
expect "*#"
send "./run_engine.sh test.pyr"
expect eof
#interact

所以如果我这样做

expect my_expect.exp

它只打印命令:

spawn ssh aaaaaa@xxx.cloud.xxx.com -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no (10s later) ssh aaaaa@xxx.xxxx.xxxx.com (10s later) cd /tmp/amz337/COAFALV (10s later) ./run_engine.sh test.py (exit)

我的脚本有什么问题?

因为Tcl(以及Expect(在变量被替换时不会改变单词边界。您正在尝试准确登录到名为:

xxx.cloud.xxx.com -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no

空间和所有。

从逻辑上讲,将ssh选项放入保存地址的变量中是没有意义的。我可以建议:

set addr1 "xxx.cloud.xxx.com"
set addr2 "xxx.xxxx.xxxx.com"
set ssh_opts($addr1) {-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no}
set ssh_opts($addr2) {}

然后

spawn ssh {*}$ssh_opts($addr1) $usrnm@$addr1

{*}语法是Tcl的"splat"运算符,它将带有空格的单词拆分为单个单词。请参阅规则 #5 https://tcl.tk/man/tcl8.6/TclCmd/Tcl.htm。

稍后,当您连接到第二台计算机时,您将插值到一个字符串中,因此不需要 splat:

send "ssh $ssh_opts($addr2) $usrnm@$addr2r"

您可能希望捕获超时事件并中止脚本:

expect {
timeout      {error "timed-out connecting to $addr1"}
"(yes/no)?"  {send "yesr"; exp_continue}
"password: " {send  "$pwdr"}
}

在脚本结束时,run_engine脚本完成后,您仍连接到 addr2,因此expect eof实际上不会在生成的进程中检测到 EOF。你将在 10 秒后超时,预期进程将退出。为了整洁,您应该:

send "./run_engine.sh test.pyr"
expect "*#"
send "exitr"
# This prompt is from addr1
expect "*#"
send "exitr"
# _Now_ the spawned ssh process will end
expect eof

如果您认为run_engine脚本将花费超过 10 秒的时间,则应在发送该命令之前调整超时变量。

此外,在开发 Expect 脚本时,应打开调试:

exp_internal 1

这将向您展示幕后发生的事情,尤其是在查看您的模式是否匹配时。

最新更新