我正在用bash编写一些expect命令。
脚本:
#!/bin/bash
set timeout -1
expect -c "
spawn telnet $IP $PORT1
sleep 1
send \"\r\"
send \"\r\"
expect Prompt1>
interact timeout 20 {
sleep 1
}
expect {
Prompt2> {send \"dir\r\" }
}
"
我对脚本的意图是,首先让它telnet到一台机器,当它看到Prompt1时,让它控制我,我将执行一个命令来加载一个特定的图像。然后等待Prompt2显示(表示图像已加载)。然后让它执行另一组命令。
运行脚本后,我可以进入交互模式,加载我的图像。问题是在远程计算机上退出交互模式并对其进行控制。
我得到的错误:
expect: spawn id exp4 not open
while executing
"expect -nobrace Prompt2 {send "dir\r" }"
invoked from within
"expect {
Prompt2 {send "dir\r" }
}"
我该怎么做?
答案 0 :(得分:6)
你的问题是双重的......
你应该与一个明确的return
互动,并给它一些方法来知道你已经释放了控制......在这种情况下,我使用三个加号并点击回车。
返回控件后,脚本需要再次获取提示,这意味着在将控制权返回到expect之后,您要做的第一件事就是发送另一个\r
。我编辑了我认为你要做的事情......
示例如下......
#!/bin/bash
set timeout -1
expect -c "
spawn telnet $IP $PORT1
sleep 1
send \"\r\"
send \"\r\"
expect Prompt1>
interact +++ return
send \"\r\"
expect {
Prompt2> {send \"dir\r\" }
}
"
答案 1 :(得分:1)
return
对我不起作用,因为就我而言,这不是一个可以简单地再次提示我相同问题的外壳。我无法弄清楚如何使其与return
之前印刷的内容相匹配。
手册说:
Upon matching a pattern (or eof or full_buffer), any matching and previously unmatched output is saved in the variable expect_out(buffer).
但是我无法使它正常工作(除非我在下面使用过它,再加上-indices
使它在那里工作,并且不知道如何使其工作以将先前的输出馈送到新的{ {1}}块。)
使用expect { ... }
的解决方案here对我也不起作用,因为它没有解释,也没有使用我想要的方式,因此不知道如何在我的实际期望文件。
所以我要做的是避免使用交互模式,而只是提供一种输入方式,一次只能一行。它甚至适用于箭头键和expect_user
(在dpkg对话框问题中),但有时不仅仅适用于alt+...
(对于<enter>
按alt + y或对<Yes>
按alt + o对于dpkg对话框中的用户)。 (有人知道如何发送回车吗?不是'\ n',而是像dpkg Dialog这样的回车键吗?)
<Ok>
部分意味着,它不仅查看用户的生成过程,还查看用户输入的内容。这会影响其后的所有内容,因此您使用-i $user_spawn_id
或将其置于其余的下方,而不是expect_after
。 expect_before
使得可以读取匹配的正则表达式的捕获部分。 -indices
是我想要的部分(冒号除外)。
expect_out(1,string)
使用expect_after {
-i $user_spawn_id
# single line custom input; prefix with : and the rest is sent to the application
-indices -re ":(.*)" {
send "$expect_out(1,string)"
}
}
意味着它将应用于随后的所有expect_after
块,直到下一个expect
。因此,您可以将其放在文件中通常的expect_after
行上方的任何位置。
我想自动执行do-release-upgrade,它不能正确支持通常的Debian非交互式标志(请参阅here)...它只是挂起并忽略输入,而不是在出现问题后继续进行。但是问题是无法预料的……升级失败意味着您可能会破坏系统,因此需要回退到交互。
答案 2 :(得分:0)
感谢迈克的建议。 我调整了一下,并根据我的问题调整了它。
更改了代码:
expect Prompt1>
interact timeout 10 return
expect {
timeout {exp_continue}
Prompt2 {send \"dir\r\" }
}
超时10值与我们初始设置的set timeout -1
无关。因此,我可以在Prompt1
上执行我想要的任何命令,一旦键盘空闲10秒钟,脚本就会获得控制权。
即使在此之后我又面临一个问题,在Prompt1
之后,我想执行命令来加载特定图像。图像加载大约需要2分钟。即使使用set timeout -1
,脚本也会等待Prompt2
。这甚至不是telnet超时,我验证了。但是解决方法是在expect语句中超时的情况下添加exp_continue。
要使set timeout -1
生效,它应该放在expect中的spawn telnet命令之前。