True, interacting with a shell reliably is not simple, but neither are many other tasks. It's taken many years of small incremental improvements to get where it is today.

# #!/usr/bin/expect -f (include this file, don't run it) # Login and logout expect procedures for Cisco SSH or telnet access # # written by Scott L. Miller # # Last modified: # 6/15/2013 By Scott L. Miller # ###################################################################### +# # Handle the login & logout procedures # # login will return the prompt string if successful # # The calling script expects return codes of 2 or less to mean the # login was unsuccessful, and 3 or more if at least the login was # successful but there were other errors. ###################################################################### +# proc connect_login { hostaddr user } { global logfile procid expect_out spawn_id set try_telnet 0 spawn /usr/bin/ssh -l $user $hostaddr expect { -gl "timeout" { puts $logfile "Connection t +imed out"; exit 1 } "timed out" { puts $logfile "Connection tim +ed out"; exit 1 } "Connection refused" { puts $logfile "Connectio +n refused ssh"; set try_telnet 1 } "uthentication failed" { puts $logfile "SSH Aut +hentication failed"; exit 1 } -re "authenticity of host .* can't be established" { expect { "connecting (yes/no)" { send "yes\r" } } } "REMOTE HOST IDENTIFICATION HAS CHANGED" { expect { -re "(Offending key \[^\r]*)" { puts $logfile "Host SSH key has changed, $expect_o +ut(1,string)"; } } exit 1 } -notransfer "assword:" { } default { puts $logfile "expect timed o +ut ssh"; exit 2 } } if { $try_telnet > 0 } { set pstr [login_telnet $hostaddr $user] } else { set procid $spawn_id catch { login_ssh } pstr } return $pstr } proc login_ssh {} { global logfile procid ropwd rwpwd expect_out spawn_id #set spawn_id $procid expect { -gl "timeout" { puts $logfile "Connection t +imed out"; exit 1 } "timed out" { puts $logfile "Connection tim +ed out"; exit 1 } "Connection refused" { puts $logfile "Connectio +n refused"; exit 1 } "assword:" { send "$ropwd\r" } default { puts $logfile "expect timed o +ut ssh login"; exit 2 } } expect { "Permission denied" { puts $logfile "Login inco +rrect"; exit 1 } "assword:" { puts $logfile "Login incorrect +"; exit 1 } #attempt to match empty line between password prompt and cisco + command prompt #"\r\n\r\n" { } "\r\n" { } "available commands.\r\n" { } default { puts $logfile "expect timed o +ut ssh passwd"; exit 2 } } catch { get_prompt_and_enable } pstr return $pstr } proc login_telnet { hostaddr user } { global logfile ropwd rwpwd expect_out spawn_id spawn telnet $hostaddr expect { "timeout" { puts $logfile "Connection timed + out"; exit 1 } "timed out" { puts $logfile "Connection tim +ed out"; exit 1 } "Connection refused" { puts $logfile "Connectio +n refused telnet"; exit 1 } "sername:" { send "$user\r" } default { puts $logfile "Connection tim +ed out"; exit 2 } } set procid $spawn_id expect { "assword:" { send "$ropwd\r" } default { puts $logfile "expect timed o +ut waiting for telnet password:"; exit 2 } } expect { "assword:" { puts $logfile "Login incorrect +"; exit 1 } "Authentication failed" { puts $logfile "Login +incorrect"; exit 1 } -notransfer -re "(>|#)" { } default { puts $logfile "expect timed o +ut after telnet password"; exit 2 } } catch { get_prompt_and_enable } pstr return $pstr } proc get_prompt_and_enable {} { global logfile procid rwpwd expect_out spawn_id expect { "assword:" { puts $logfile "Login incorrect +"; exit 1 } -re "(\[a-zA-Z0-9_@\\-: ]*)(>|#)" { #### grab the prompt string to simplify prompt recognition & he +lp eliminate false positives set pstr $expect_out(1,string) set plvl $expect_out(2,string) #yeah, the bare '>' below is correct, but I don't like the + way it looks either if { [string equal $plvl >] } { send "enable\r" expect { "assword:" { send "$rwpwd\r" } default { puts $logfile "ex +pect timed out during enable"; exit 2 } } expect { "Access denied" { puts $logfile + "Enable Login incorrect"; exit 1 } -notransfer "[set pstr]#" { } default { puts $logfile "ex +pect timed out after enable passwd"; exit 2 } } } send "\r" } default { puts $logfile "expect timed o +ut while identifying prompt string"; exit 2 } } expect { -notransfer "[set pstr]#" { } default { puts $logfile "expect timed o +ut after enable mode"; exit 3 } } return $pstr } ###################################################################### +### # remember, all the expect pre- and post- tests are still active, # That's why we need the "global ... " statement ###################################################################### +### proc logout {} { global pstr logfile lastcmd errorcount expect_after { #The work is done, we're just trying to shutdown cleanly, If t +his #shutdown attempt is ALL that fails, there's no sense in sayin +g the #operations failed. Unless of course the operations did fail.. +. default { puts $logfile "expect timed out after \'$lastcmd\', exitin +g with $errorcount status" exit $errorcount } } expect "[set pstr]#" { send "exit\r" } expect { "\r\n" { close } } wait; } # # vim:ai:ts=8:sw=8
-Scott

In reply to Re^2: Off Topic: Looking for good Expect scripts by 5mi11er
in thread Off Topic: Looking for good Expect scripts by 5mi11er

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.