How to use expect with optional prompts? - linux

Let's say I am trying to write an expect script for a test.sh that has three prompts: prompt1, prompt2, prompt3.
My code is like this:
spawn test.sh
expect "prompt1"
send "pass1"
expect "prompt2"
send "pass2"
expect "prompt3"
send "pass3"
However, prompt2 only occurs half the time. If prompt2 doesn't show up, the expect script breaks. How would I write expect code that skips over prompt2 if it doesn't show up?
EDIT:
Fixed my code:
/usr/bin/expect -c '
spawn ./test.sh
expect {
"prompt1" {
send "pass1\r"
exp_continue
}
"prompt2" {
send "pass2\r"
exp_continue
}
"prompt3" {
send "pass3\r"
exp_continue
}
}
interact return
'
This way, the rest of the script executes and provides output.

As long as you have a case that will be always be expected to hit and don't include an exp_continue in that case, you can can remove duplication and handle optional prompts easily:
expect "prompt1"
send "pass1"
expect {
"prompt2" {
send "pass2"
exp_continue
}
"prompt3" {
send "pass3"
}
}

You can expect multiple things:
expect {
"prompt2" {
send "pass2"
expect "prompt3"
send "pass3"
}
"prompt3" {
send "pass3"
}
}

Related

Use 'expect' in Bash with responses in any order

I'm using this expect file (keygen.exp) to generate SSH key, I'm using ssh-keygen just as example to test 'expect':
#!/usr/bin/expect
spawn ssh-keygen
expect "Enter file"
send "./id_rsa\r"
expect "Enter passphrase"
send "\r"
expect "Enter same passphrase"
send "\r"
interact
It works perfectly, however, what if the order of the prompts for inputs is not the same every run, and there might be different questions on different runs?
I want something like this:
#!/usr/bin/expect
spawn ssh-keygen
expect if-is "Enter file"
send "./id_rsa\r"
expect if-is "Enter passphrase"
send "\r"
expect if-is "Enter same passphrase"
send "\r"
interact
Is it possible?
You can have single expect statement which loops, processing different outputs differently, something like:
expect {
"Enter file" {
send "./id_rsa\r"
exp_continue
}
"Enter passphrase" {
send "\r"
exp_continue
}
"Enter same passphrase" {
send "\r"
exp_continue
}
$
}
But note that you need some way to break out of the loop. The last pattern here - $ has no exp_continue (or any other action) so it will break out of the loop if the prompt you get when logged in includes $.
See the full documentation at https://www.tcl.tk/man/expect5.31/expect.1.html
Expect in any order, with infinite timeout:
#!/usr/bin/expect
spawn /path/to/some-programme
expect {
"some string" {
set timeout -1
send "some input\r"
exp_continue
}
"some other string" {
set timeout -1
send "some other input\r"
exp_continue
}
...
}
#no 'interact'
#end of file

How to have Expect script output to file

I need to gather some statistics from a network switch and would like to use an expect script to output the data to a file. I would like to run this script as a cron job and have the data appended to the file when it is run. Following is the working code I have so far, I just do not know how to get the output to a file. Any help is greatly appreciated.
#!/bin/bash
#get mac-address count
/usr/bin/expect -f -<<EOD
spawn ssh user#192.168.1.100
sleep 2
#Catch the password prompt and send supplied password
expect {
"*word:" {send "password\r"}
}
sleep 1
#Get into enabled mode
expect {
"*>" {send "system-view\r"}
}
sleep 1
expect {
"*]" {send "display mac-address count\r"}
}
sleep 1
expect {
"*]" {send "quit\r"}
}
sleep 1
expect {
"*>" {send "quit\r"}
}
sleep 1
expect eof
EOD

What does the number after `exit` command in expect scripts mean

I am looking at an expect script at it has the following lines:
#some heading
send -- "some command\n"
expect {
-re $more {
send -- " "
exp_continue
}
">" { }
default { exit 230 }
}
# some heading
send -- "some command\n"
expect {
-re $more {
send -- " "
exp_continue
}
">" { }
default { exit 211 }
}
So what do the numbers "230" and "211" mean after the exit command.
The numbers are exit codes. They range from 0-255 and are used to communicate program success or errors to other applications that might invoke that program (e.g. your shell).
In bash and many other shells, you can check the exit status of the last program using $?. An exit status of 0 indicates success, any non-0 status means failure. You should refer to the program's documentation to see what the different exit codes could mean.
See also the Wikipedia entry on exit status.

expect program send commands from file

How to make send command of "expect" program to read from a file and use each line as argument.
I want to use a loop like structure in expect program which may look like below(NOTE:- while loop is imaginary.)
spawn /my/program
expect {
-re EBtxjjmEcQTxc0SLd4TdXxjUduxCOLZBwEme2Z.*password: {
while read_line in FILE;
do
send $read-line;
done
}
How to program the while-loop part equivalent using "expect"
Note in your question, you were missing a close brace, and you mis-typed your variable name (read_line and read-line)
Expect is a Tcl extension, so you have all the Tcl commands at your disposal
spawn /my/program
expect {
-re EBtxjjmEcQTxc0SLd4TdXxjUduxCOLZBwEme2Z.*password: {
set fh [open FILE r]
while {[gets $fh read_line] != -1} {
send "$read_line\r"
}
close $fh
}
}
If you install tcllib, you can do
package require fileutil
spawn /my/program
expect {
-re EBtxjjmEcQTxc0SLd4TdXxjUduxCOLZBwEme2Z.*password: {
fileutil::foreachLine read_line FILE {
send "$read_line\r"
}
}
}

How to return spawned process exit code in Expect script?

I use expect for running test scripts.
Tests return success/failure through exit code. But expect return equivalent exit code.
How to make expect return proper exit status?
My tests are sql scripts run with psql (postgresql command processor).
Since psql doesn't allow to specify database password as a command line parameter, expect scripts do that.
So, my expect script looks like:
spawn $SPAWN_CMD
expect {
-re "Enter password for new role:" {
send "$PWPROMPT\n"
exp_continue
} -re "Enter it again:" {
send "$PWPROMPT\n"
exp_continue
} -re "Password(.*)" {
send "$PASSWORD\n"
exp_continue
} -re "Password(.*):" {
send "$PASSWORD\n"
exp_continue
} eof
}
You're already waiting for the eof at the end of your loop, you just need to use wait and catch the result:
spawn true
expect eof
catch wait result
exit [lindex $result 3]
Exits with 0.
spawn false
expect eof
catch wait result
exit [lindex $result 3]
Exits with 1.

Resources