Использование условных операторов внутри 'expect'

Мне нужно автоматизировать вход в сеанс TELNET с помощью ожидал, но мне нужно позаботиться о нескольких паролей для одного пользователя.

вот поток, который мне нужно создать:

  1. откройте сеанс TELNET на IP
  2. отправить имя пользователя
  3. отправить пароль
  4. Неправильный пароль? Отправьте то же имя пользователя еще раз, затем другой пароль
  5. должен был успешно войти в систему при этом точка...

для чего это стоит, вот что у меня есть до сих пор:

#!/usr/bin/expect
spawn telnet 192.168.40.100
expect "login:"
send "spongebobr"
expect "password:"
send "squarepantsr"
expect "login incorrect" {
  expect "login:"
  send "spongebobr"
  expect "password:"
  send "rhombuspantsr"
}
expect "prompt>" {
  send_user "success!r"
}
send "blah...blah...blahr"

Излишне говорить, что это не работает, и это не выглядит очень красиво. Из моих приключений с Google ожидал кажется, что-то вроде темного искусства. Заранее спасибо всем за помощь в этом вопросе!

3 ответов


должны рекомендовать Исследуя Ожидать книга для всех ожидаемых программистов -- бесценна.

я переписал ваш код: (непроверено)

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 возвращается к началу блока expect - это похоже на оператор "redo".

отметим, что send_user заканчивается \n не \r

вам не нужно бежать > символ в вашем приглашении: это не специально для Tcl.


с небольшим избиением я нашел решение. Оказывается, 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

надеюсь, это будет полезно другим.


Если вы знаете идентификаторы пользователей и пароли, то вы также должны знать, какие пары userid/password выровнены с какими системами. Я думаю, вам было бы лучше поддерживать карту того, какая пара userid/password идет с какой системой, а затем извлекать эту информацию и просто использовать правильный.

Итак -- поскольку вам явно не нравится мой совет, тогда я предлагаю вам посмотреть на Википедия страницы и реализовать процедуру, которая возвращает 0, если успешно и 1, Если время ожидания истекло. Это позволит вам определить, когда поставляемый пароль не удался - время ожидания запроса истекло - и повторить попытку. Если это полезно, вы можете удалить свой downvote теперь, когда я его отредактировал.

в ретроспективе, вы, вероятно, захотите сделать это в сочетании с картой в любом случае, так как вы хотите обнаружить неудачный вход в систему, если пароль был изменен.