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

时间:2011-04-09 01:35:46

标签: expect

我正在用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" }  
}"  

我该怎么做?

3 个答案:

答案 0 :(得分:6)

你的问题是双重的......

  1. 你应该与一个明确的return互动,并给它一些方法来知道你已经释放了控制......在这种情况下,我使用三个加号并点击回车。

  2. 返回控件后,脚本需要再次获取提示,这意味着在将控制权返回到expect之后,您要做的第一件事就是发送另一个\r。我编辑了我认为你要做的事情......

  3. 示例如下......

    #!/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之前印刷的内容相匹配。

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使它在那里工作,并且不知道如何使其工作以将先前的输出馈送到新的{ {1}}块。)

expect_user

使用expect { ... }的解决方案here对我也不起作用,因为它没有解释,也没有使用我想要的方式,因此不知道如何在我的实际期望文件。

我的解决方案

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

<Ok>部分意味着,它不仅查看用户的生成过程,还查看用户输入的内容。这会影响其后的所有内容,因此您使用-i $user_spawn_id或将其置于其余的下方,而不是expect_afterexpect_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命令之前。