【问题标题】:Using conditional statements inside 'expect'在“期望”中使用条件语句
【发布时间】:2010-12-05 00:54:32
【问题描述】:

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

这是我需要创建的流程:

  1. 打开到 IP 的 TELNET 会话
  2. 发送用户名
  3. 发送密码
  4. 密码错误?再次发送相同的用户名,然后发送不同的密码
  5. 此时应该已经成功登录...

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

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

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

【问题讨论】:

  • 我在回答中添加了更多信息。

标签: bash automation telnet expect conditional-statements


【解决方案1】:

经过一番抨击,我找到了解决方案。事实证明,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

希望这对其他人有用。

【讨论】:

  • 我对 SSH 使用了类似的解决方案,但从密码文件“~/.ssh/ssh-passwords”中读取密码。主机名和用户名是从我的“~/.ssh/config”文件中读取的。所以运行: 'cssh server1' 将扩展到 ubuntu@server1.mycompany.com
  • 我是 Expect 的新手,expect { "case1"{...} "case2"{...} "case3"{...}} 是不是某种 switch case像 C++ 这样的语句?谢谢
  • @B.Mr.W.是的,在外部使用它 {} 基本上会使其失败,而不是单独的 if 语句
【解决方案2】:

必须向所有期望程序员推荐Exploring Expect 书——非常宝贵。

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

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_continue 循环回到期望块的开头——这就像一个“重做”语句。

注意send_user\n 结尾,而不是\r

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

【讨论】:

    【解决方案3】:

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

    所以——既然您显然不喜欢我的建议,那么我建议您查看wikipedia page 并实施一个过程,如果成功则返回 0,如果期望超时则返回 1。这将允许您检测提供的密码何时失败(提示预期超时)并重试。如果这有帮助,您可以在我编辑后删除您的反对票。

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

    【讨论】:

    • 很抱歉投了反对票。我打了一个很长的电话,想要一种快速的方式来表明我还没有答案,而无需输入帖子来解释原因。无论如何,如果我有一种可靠的方法来记录某些设备上使用的密码,我当然不会使用条件方法。它可以在我无法控制的固件版本中更改,所以我所能做的就是准备好一个密码列表以供试用。我明白我需要做什么——使用条件语句并根据答案采取行动——我只是不知道该怎么做。 :)
    • 您现在可以删除我已编辑的投票 - 也就是说,如果附加信息有帮助或至少不会使帖子无用。只要您不接受答案,人们就可能会继续添加答案 - 尽管您可能希望使用有关为什么难以跟踪密码的信息来更新您的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多