5

I am trying to automate switch commands. It's almost all good, but when the expect script reads each line from the file containing my switch commands (listed line by line), the switch seems to stop after about 10 or 15 commands, i think the buffer is too small.

How can I add in a sleep between each command that is read from the file? Thanks!!

set fp [open "/home/room.txt" r]
set data [read $fp]

set timeout -60
spawn telnet 10.91.60.14
match_max 100000
sleep 2
expect *
send -- "^Y"
sleep 2
send -- "password\r"
sleep 2
send -- "^[\[A"
send -- "^[\[A"
send -- "\r"
sleep 1
send -- "enable\r"
send -- "configure terminal\r"
sleep 1
expect *
sleep 2
**send -- "$data"**
sleep 2
interact
2legit2quit
  • 171
  • 1
  • 2
  • 10
  • 2
    Instead of sleeping between `send`s, you should be `expect`ing a pattern to appear first. For instance, between sending commands to your switch, you should expect to see the command prompt. It's often helpful to record a manual session with `autoexpect`. – glenn jackman Mar 01 '16 at 13:44
  • Hi Glenn okay thank you. so I know I just need a "#" for expect since thats the switch prompt, but, if I add an expect before the send $data, will it still wait for the prompt for each line from the file? – 2legit2quit Mar 01 '16 at 20:39
  • No, you'll want to follow thrig's solution. – glenn jackman Mar 01 '16 at 21:34

3 Answers3

2

So, older discussion but after wrestling with expect over the past day or two and gathering several helpful hints from users here and elsewhere I decided to post what I had found. I am also on a Mac not native Linux for this so some things were quirky. This script is called from a bash script with:

expect -d <filename>.expect

If #!<PATH to expect> -f is implemented in the top line of your *.expect file AND you:

chmod +x <filename>.expect your file this will work. The -d is for additional debug info.

Call expect with: expect -df <filename>.expect in your bash script to accomplish the same effect and you do not need executable rights on the file.

The debug info is very helpful on seeing your expect statements, variables, etc. like this:

spawn <program> <args>
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {29747}

expect: does "" (spawn_id exp10) match glob pattern "Please enter 
passphrase:"? no
Please enter passphrase:
expect: does "Please enter passphrase: " (spawn_id exp10) match glob 
pattern "Please enter passphrase:"? yes
expect: set expect_out(0,string) "Please enter passphrase:"
expect: set expect_out(spawn_id) "exp10"
expect: set expect_out(buffer) "Please enter passphrase:"

Here is the short bash script, (only an example, but helpful if you need it to do more complex stuff or just call it from bash for some reason)

#!/bin/bash

expect -d exp.expect "$WORD"
RET=$?

if [ $RET -eq 1 ]; then
    #mac specific, sheer laziness, allows me to do other stuff...
    #use esay or similar on Linux
    say "Query was found, expect returned success" 
    echo *************************************************** 
    echo ******************FOUND!***************************
fi
exit 0

Here is the expect script:

#!/usr/bin/expect -f
#capture logs for debugging
log_file -a log_file.txt

#dont timeout, let the program run its course, (was mandatory for me)
set timeout -1;

#capture all of our output for debugging
set output [ open "output.txt" "RDWR" ];

#This procedure is called repeatedly with the next word
proc check_word {w} {

#kickoff our other program we are going to talk to
spawn <program> <args>

#we want this one to go regardless, the next 2 are mutex
expect "Please enter passphrase:" { send "$w\r"; send_user "\nSENDING: $w\r"; send_user "\nOutput BUFFER: $expect_out(buffer)\n" }

#These are mutually exclusive, either worked or not, can be grouped
expect {
"scrypt: Passphrase is incorrect" { send_user "\n*FAILED*\n"; close }
-re {anders} { send_user "$expect_out(buffer)\n"; close; exit 1 }
}
#wait for the process to end, timeout is set to never expire
wait
}

#open the file to take the words from, (happens before proc above)
set input [ open "words.txt" "RDONLY" ];

#while there are still words, (we exit on a match) ...keep going....
while {[gets $input word] != -1} {
        check_word $word;
}
#close input file, TODO do this upon success in expect call too?
close $input
close $words

#EOF

Hopefully this helps some/anyone save some time out there!

eulerworks
  • 151
  • 5
1

Use a while loop:

set fp [open "datfile"]
while {[gets $fp line] >= 0} {
  puts $line
  #sleep 3
  # but better to wait for the prompt
  expect #
}
thrig
  • 1,626
  • 9
  • 9
  • That won't work: `read` returns a single string, so `$line` will be the entire file. You need `while {[gets $fp line] != -1} {...}` or `foreach line [split [read -nonewline $fp] \n] {...}`. But again, sleeping is the wrong strategy. – glenn jackman Mar 01 '16 at 13:46
  • @glennjackman curious, contrary to the Tcl `read` docs, the `foreach` construct reads linewise for me (expect 5.44 or 5.45). – thrig Mar 01 '16 at 17:34
  • OK, I see what's happening: `read` does slurp the entire file. However that data is the 2nd argument to `foreach`, so it gets implicitly treated like a **list**. The data is split on whitespace and foreach is iterating over the *words* of the file, not the *lines*. If the file contains an unmatched open brace, you'll see errors about an invalid list. – glenn jackman Mar 01 '16 at 17:40
  • General Tcl rule of thumb: use string commands on strings and list commands on lists. If you want to handle a string as a list, `split` it first. – glenn jackman Mar 01 '16 at 17:43
  • @glennjackman okay, I think I've beaten the code into line-reading-but-not-the-implicit-blank-line-after-the-ultimate-newline shape. – thrig Mar 01 '16 at 18:22
  • That's what `read -nonewline` is for. – glenn jackman Mar 01 '16 at 18:58
  • OK, now: which do you prefer: the foreach loop or the while loop? – glenn jackman Mar 01 '16 at 19:06
  • :/ :O uf. i have so much to learn. im lost. ill have to read through this properly.. – 2legit2quit Mar 01 '16 at 20:53
-1

your script should look like this:

set passwd {your_login_password_here}
set en "enable"
#
spawn telnet $rtr
expect {
    timeout { puts " ###   $rtr  TIMEOUT   ###"
              exit
    } 
    "ername:" { send "$env(USER)\r"  
                expect {
                   {*ssword} { send "$passwd\r" }
                }
     }
}
expect {
   {*>}  { send "$en\r"
           expect {
              "ername:" { send "$env(USER)\r"
                         expect {
                             {*ssword} { send "$passwd\r" }
                         }
               }
               "*ssword" { send "$passwd\r" }
           }
   }
}
expect {
   "#"  { send "conf t\r" }
}
set load_cmd [open "open "/home/room.txt" r]
set cmd_list [split [read $load_cmd] "\n"]
close $load_cmd
expect {
        {#} { foreach command $cmd_list {
                if {$command != ""} {
                   send "$command\n"
                }
              } 
        } 
}
interact
kasperd
  • 29,894
  • 16
  • 72
  • 122