Multiple patterns with expect. Handling a SSH login dialog.

When automating network tasks, you a can hit a node which you have not logged on earlier. Using SSH you will end up in a dialog where the ssh client wants to add ssh-key to the known key list. You will hit a wall when using expect in a rather unsophisticated way, e.g.:

expect "this"
send "that\r"

Expect provides a way to conditionally send answers;

expect {
      "pattern_a" { send "answer_a\r"}
      "pattern_b" { send "answer_b\r"}
}

This resembles a construction like switch/case known in other programming/scripting languages. Like any other proper switch/case statement there is a default to act like a catch all. Like most programming/scripting languages it is possible to nest statements. Take a look at the next code ;

expect {
  "outer pattern_a" { 
    send "answer_a\r"}
  "outer pattern_b" {
    send "answer_b\r"
    #nesting starts------------------------
    expect {
      "inner pattern" {
        send "answer inner pattern\r" }
      default {
        send_user "Inner pattern not found\r"
        exit }
    }
    #nesting ends--------------------------
  } 
  #default behavior defined below.
  default {
    send_user "Pattern not found, bugging out\n"
    exit
  }
}

Nesting easily confuses the code, keep your code clearly readable. Provide comments in your code, to enable you to troubleshoot your own code in the future.

For a ssh login dialog you need to program the following steps;

#!/usr/bin/expect

set user uberuser
set passwd SuPeRseCriT
# grab the first argument and use it as var $host
set host [lindex $argv 0]

#set the timeout to a pleasantly low number, but not too low. 
set timeout 2

spawn ssh $user@$host

#--login shizzle starts here -------------------------------------------------
expect {
  "yes/no" {
    send "yes\r"
    #-- nesting start -- yes/no -> passwd dialog -----------------------------
    expect { 
      "assword:" {
        send "$passwd\r"
        #catch all undefined patterns
        default {
          send_user "Login failure\n"
          exit
        }
      }
      #-- nesting ends -- yes/no -> passwd dialog ----------------------------
      # catch all undefined patterns
       default {
         send_user "Login failure\n"
         exit                 
       }
     } 
   } 
   "assword:" {  
     send "$passwd\r"
     expect {
       ">" { exp_continue }  
       default { 
         send_user "Login failure\n"
         exit
       } 
    }     
  }
  default {
    send_user "Login failed\n"
    exit
  }
}
#--login shizzle ends here----------------------------------------------------

# Your magic goes here.. or
interact
# and type the commands your self :D

This code will effectively handle the ssh yes/no dialog. I tend to keep my code as tidy as possible in regards of comment, tabs and braces. This helps read the code afterwards.

It may seem redundant to this many “default” sections, but you want to handle wrong usernames as well. Which is handled implicit.

Hopefully this will help you understanding expect somewhat more.

This entry was posted in TCL/Expect. Bookmark the permalink.