我怎么知道我已经完成了交互模式?

问题描述 投票:5回答:3

我正在用bash写一些期望命令。

脚本:

#!/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\" }  
}    

"  

我使用脚本的目的是,首先让它远程登录到计算机,当它看到Prompt1时,让它提供控制权,我将执行命令以加载特定的图像。然后等待,直到Prompt2出现(表明图像已加载)。然后让它执行其他命令集。

运行脚本后,我可以进入交互模式,加载我的图像。问题是退出远程计算机上的交互模式,并将控制权交还给它。

我得到的错误:

expect: spawn id exp4 not open  
    while executing  
"expect -nobrace Prompt2 {send "dir\r" }"  
    invoked from within  
"expect {    
Prompt2 {send "dir\r" }  
}"  

我该怎么做?

expect
3个回答
6
投票
您的问题有两个...

  1. 您应该与显式return进行交互,并提供某种方式来知道您已释放控制权...在这种情况下,我使用三个加号并按Enter。
  2. 返回控件后,脚本将需要再次获得提示,这意味着返回控件后期望执行的第一件事是发送另一个\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\" } } "


0
投票
感谢Mike的建议。我对其进行了一些调整,以使其适应我的问题。

更改的代码:

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超时。但是解决方案是在expected语句中添加超时情况下的exp_continue。

为了使您的set timeout -1生效,应将其放置在期望值中的spawn telnet命令之前。


0
投票
返回=失败

return不适用于我,因为就我而言,这不是一个可以简单地再次提示我相同问题的外壳程序。在执行return之前,我不知道如何使它与打印的内容相匹配。

expect_out(用于解决上述问题)=失败

手册说:

Upon matching a pattern (or eof or full_buffer), any matching and previously unmatched output is saved in the variable expect_out(buffer).

但是我无法使它正常工作(除非我在下面使用过它,再加上-indices使它在那里工作,而且不知道如何使它工作以将先前的输出馈送到新的expect { ... }块中。)

expect_user

并且使用here的解决方案expect_user对我也不起作用,因为它没有解释,也没有使用我想要的方式,因此也不知道如何在我的实际期望文件中应用这个有限的示例。

我的解决方案

因此,我要做的是避免使用交互模式,而只是有一种提供输入的方法,一次只能一行。它甚至适用于箭头键和alt+...(在dpkg对话框问题中),但有时不适用于简单的<enter>(对于dpkg对话框中的<Yes>命中alt + y或<Ok>的alt + o)。 (有人知道如何发送回车吗?不是'\ n',而是像dpkg Dialog这样的回车键吗?)

-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为止。因此,您可以将其放在文件中通常expect行的上方。

和我的案情/目的

我想自动执行do-release-upgrade,它不能正确支持通常的Debian非交互式标志(请参见here)...它只是挂起并忽略输入,而不是在出现问题后继续进行。但是问题是无法预料的……升级失败意味着您可能会弄乱系统,因此需要回退到交互。

© www.soinside.com 2019 - 2024. All rights reserved.