bash 在“期望”中使用条件语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1538444/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:35:56  来源:igfitidea点击:

Using conditional statements inside 'expect'

bashautomationtelnetexpectconditional-statements

提问by shuckster

I need to automate logging into a TELNET session using expect, but I need to take care of multiple passwords for the same username.

我需要使用expect自动登录到 TELNET 会话,但我需要处理同一个用户名的多个密码。

Here's the flow I need to create:

这是我需要创建的流程:

  1. Open TELNET session to an IP
  2. Send user-name
  3. Send password
  4. Wrong password? Send the same user-name again, then a different password
  5. Should have successfully logged-in at this point...
  1. 打开到 IP 的 TELNET 会话
  2. 发送用户名
  3. 发送密码
  4. 密码错误?再次发送相同的用户名,然后发送不同的密码
  5. 此时应该已成功登录...

For what it's worth, here's what I've got so far:

对于它的价值,这是我到目前为止所得到的:

#!/usr/bin/expect
spawn telnet 192.168.40.100
expect "login:"
send "spongebob\r"
expect "password:"
send "squarepants\r"
expect "login incorrect" {
  expect "login:"
  send "spongebob\r"
  expect "password:"
  send "rhombuspants\r"
}
expect "prompt\>" {
  send_user "success!\r"
}
send "blah...blah...blah\r"

Needless to say this doesn't work, and nor does it look very pretty. From my adventures with Google expectseems to be something of a dark-art. Thanks in advance to anyone for assistance in the matter!

不用说这行不通,而且看起来也不是很漂亮。从我与 Google 的冒险经历来看,expect似乎是一种黑暗艺术。在此先感谢任何人的帮助!

回答by glenn Hymanman

Have to recomment the Exploring Expectbook for all expect programmers -- invaluable.

必须为所有expect 程序员推荐Exploring Expect书——非常宝贵。

I've rewritten your code: (untested)

我已经重写了你的代码:(未经测试)

proc login {user pass} {
    expect "login:"
    send "$user\r"
    expect "password:"
    send "$pass\r"
}

set username spongebob 
set passwords {squarepants rhombuspants}
set index 0

spawn telnet 192.168.40.100
login $username [lindex $passwords $index]
expect {
    "login incorrect" {
        send_user "failed with $username:[lindex $passwords $index]\n"
        incr index
        if {$index == [llength $passwords]} {
            error "ran out of possible passwords"
        }
        login $username [lindex $passwords $index]
        exp_continue
    }
    "prompt>" 
}
send_user "success!\n"
# ...

exp_continueloops back to the beginning of the expect block -- it's like a "redo" statement.

exp_continue循环回到期望块的开头——就像一个“重做”语句。

Note that send_userends with \nnot \r

注意send_user\nnot结尾\r

You don't have to escape the >character in your prompt: it's not special for Tcl.

您不必>在提示中对字符进行转义:它对 Tcl 来说并不特殊。

回答by shuckster

With a bit of bashing I found a solution. Turns out that expect uses a TCL syntax that I'm not at all familiar with:

经过一番抨击,我找到了解决方案。事实证明,expect 使用了我完全不熟悉的 TCL 语法:

#!/usr/bin/expect
set pass(0) "squarepants"
set pass(1) "rhombuspants"
set pass(2) "trapezoidpants"
set count 0
set prompt "> "
spawn telnet 192.168.40.100
expect {
  "$prompt" {
    send_user "successfully logged in!\r"
  }
  "password:" {
    send "$pass($count)\r"
    exp_continue
  }
  "login incorrect" {
    incr count
    exp_continue
  }
  "username:" {
    send "spongebob\r"
    exp_continue
  }
}
send "command1\r"
expect "$prompt"
send "command2\r"
expect "$prompt"
send "exit\r"
expect eof
exit

Hopefully this will be useful to others.

希望这对其他人有用。

回答by tvanfosson

If you know the user ids and passwords, then you ought also to know which userid/password pairs are aligned with which systems. I think you'd be better off maintaining a map of which userid/password pair goes with which system then extracting that information and simply use the correct one.

如果您知道用户 ID 和密码,那么您还应该知道哪些用户 ID/密码对与哪些系统对齐。我认为您最好维护一个映射,其中包含哪个用户 ID/密码对与哪个系统对应,然后提取该信息并简单地使用正确的信息。

So -- since you obviously don't like my advice, then I suggest you look at the wikipedia pageand implement a procedure that returns 0 if successful and 1 if the expectation times out. That will allow you to detect when the password supplied failed -- the prompt expectation times out -- and retry. If this is helpful, you can remove your downvote now that I've edited it.

所以——既然你显然不喜欢我的建议,那么我建议你查看维基百科页面并实现一个程序,如果成功则返回 0,如果期望超时则返回 1。这将允许您检测提供的密码何时失败 - 提示期望超时 - 并重试。如果这有帮助,您可以在我编辑后删除您的反对票。

In retrospect, you'd probably want to do this in conjunction with the map anyway since you'd want to detect a failed login if the password was changed.

回想起来,您可能无论如何都希望与地图一起执行此操作,因为您希望在更改密码时检测登录失败。