我如何知道我已经完成了交互模式?

发布于 2024-10-31 07:15:29 字数 687 浏览 1 评论 0原文

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

"  

我对脚本的意图是,首先让它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" }  
}"  

我该怎么做?

I am writing some expect commands in bash.

Script:

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

"  

My intentions with the script are, first let it telnet into a machine, when it sees Prompt1, let it give control to me, I will execute a command to load a specific image. Then wait until Prompt2 shows up (which indicates image has been loaded). Then Let it execute the further set of commands.

After running the script, I could get into the interactive mode, load my image. The problem is getting out of interactive mode on the remote machine and giving back control to it.

The Error which I got:

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

How can I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心如狂蝶 2024-11-07 07:15:29

你的问题有两个......

  1. 你应该与显式的 return 交互,并给它一些方法来知道你已经释放了控制......在这种情况下,我使用三个加号符号并按回车键。

  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\" }  
}
"

Your problem is two-fold...

  1. You should interact with an explicit return, and give it some way to know you've released control... in this case, I use three plus signs and hit enter.

  2. After you return control, the script will need to get the prompt again, which means the first thing you do after returning control to expect is send another \r. I edited for what I think you're trying to do...

Example follows...

#!/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\" }  
}
"
骷髅 2024-11-07 07:15:29

return = failure

return 对我不起作用,因为就我而言,它不是一个可以简单地再次提示我相同问题的 shell。在返回之前,我不知道如何让它与打印的内容相匹配。

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

以及解决方案 这里使用expect_user对我来说也不起作用,因为它没有解释并且没有按照我想要的方式使用,所以不知道如何应用这个有限的例子我的实际期望文件。

我的解决方案

所以我所做的就是避免交互模式,而只是有一种方式提供输入,一次一行。它甚至适用于箭头键和 alt+...(在 dpkg 对话框问题中),但有时不适用于简单的 (按 alt+y 表示 对于 dpkg 对话框中的内容,或 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 非交互式标志(请参阅此处< /a>)...它只是挂起并忽略输入,而不是在问题之后继续。但问题是不可预测的......并且中止升级意味着您可能会弄乱您的系统,因此需要一些交互回退。

return = fail

return didn't work for me because in my case, it was not a shell that can simply prompt me again with the same question. I couldn't figure out how to get it to match on what was printed before I did return.

expect_out (to fix above solution) = fail

The manual says:

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

But I couldn't get that to work (except where I used it below, combined with -indices which makes it work there, and no idea how to make it work to get previous output fed into a new expect { ... } block.)

expect_user

And the solution here using expect_user didn't work for me either because it had no explanation and wasn't used how I wanted, so didn't know how to apply this limited example in my actual expect file.

my solution

So what I did instead was avoid the interactive mode, and just have a way to provide input, one line at a time. It even works for arrow keys and alt+..., (in dpkg Dialog questions) but not for simply <enter> sometimes (hit alt+y for <Yes> or alt+o for <Ok> for those in dpkg Dialog). (anyone know how to send an enter? not '\n', but the enter key like dpkg Dialog wants?)

The -i $user_spawn_id part means that instead of only looking at your spawned process, it also looks at what the user types. This affects everything after it, so you use expect_after or put it below the rest, not expect_before. -indices makes it possible to read the captured part of the regular expression that matches. expect_out(1,string) is the part I wanted (all except the colon).

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)"
    }
}

Using expect_after means it will apply to all following expect blocks until the next expect_after. So you can put that anywhere above your usual expect lines in the file.

and my case/purpose

I wanted to automate do-release-upgrade which does not properly support the usual Debian non-interactive flags (see here)...it just hangs and ignores input instead of proceeding after a question. But the questions are unpredictable... and an aborted upgrade means you could mess up your system, so some fallback to interaction is required.

清风不识月 2024-11-07 07:15:29

感谢迈克的建议。
我对其进行了一些调整并使其适应我的问题。

更改代码:

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命令之前。

Thanks Mike for that suggestion.
I tweaked it a bit and adapted it to my problem.

Changed code:

expect Prompt1>  
interact timeout 10 return  
expect {  
timeout {exp_continue}  
Prompt2 {send \"dir\r\" }  
}  

The timeout 10 value is not related to the set timeout -1 we set initally. Hence I can execute whatever commands I want on Prompt1 and once keyboard is idle for 10 seconds then script gains control back.

Even after this I faced one more problem, After Prompt1, I wanted to execute command to load a particular image. The image loading takes around 2 minutes. Even with set timeout -1 the script was timing out waiting for Prompt2. It's not the telnet timeout even, which i verified. But the solution for this is the adding exp_continue in case of timeout within the expect statement.

For your set timeout -1 to take into effect it should be placed before the spawn telnet command within expect.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文