expect, interact and then again expect
You can read (expect_user
) the user's password by yourself and then send
it to the spawn'ed program. For example:
[STEP 101] # cat foo.exp
proc expect_prompt {} \
{
global spawn_id
expect -re {bash-[.0-9]+(#|\$)}
}
spawn ssh -t 127.0.0.1 bash --noprofile --norc
expect "password: "
stty -echo
expect_user -timeout 3600 -re "(.*)\[\r\n]"
stty echo
send "$expect_out(1,string)\r"
expect_prompt
send "exit\r"
expect eof
[STEP 102] # expect foo.exp
spawn ssh -t 127.0.0.1 bash --noprofile --norc
root@127.0.0.1's password:
bash-4.3# exit
exit
Connection to 127.0.0.1 closed.
[STEP 103] #
Difference between interact, expect and exit in expect script
exit
does what you think it does: exit the script immediately
interact
returns control to the human: if there are things to enter manually after the script gives the auth user and passwd, the human must enter them.
expect
watches the spawned process for patterns, and when a pattern is matched the script proceeds to the next instruction.
expect Interact reads the matched line over and over again without moving onward
Imagine you're giving instructions to someone:
- if you see a red light then stop
- if you see a red light then go
You wouldn't be surprised if they get confused. That's what you're doing to Expect with multiple -re $prompt
branches. However Expect just takes the first instruction you tell it.
Try this:
interact {
-o
-re $prompt {
send "export VARIABLE1=\"$working_dir\"\r"
send "issue-test-command -config $config -module $tcl_test\r"
}
}
BTW:
- you're missing
exp_continue
aftersend "yes\r"
- you're sending the wrong number of double quotes on the
export
command
How do I tell expect that I have finished the interactive mode?
Your problem is two-fold...
You should interact with an explicit
return
, and give it some way to know you've released control... in this case, I use three plus signs and hit enter.After you return control, the script will need to get the prompt again, which means the first thing you do after returning control to expect is send another
\r
. I edited for what I think you're trying to do...
Example follows...
#!/bin/bash
set timeout -1
expect -c "
spawn telnet $IP $PORT1
sleep 1
send \"\r\"
send \"\r\"
expect Prompt1>
interact +++ return
send \"\r\"
expect {
Prompt2> {send \"dir\r\" }
}
"
How to set the Interact timeframe for expect
This uses the Tcl after
command to schedule code to run after X milliseconds
spawn -noecho telnet IP
proc get_user_time_in_milliseconds {username} {
# checks here
set limit 5000 ;# => 5 seconds
return $limit
}
proc byebye {spawn_id} {
send_user "\n\nYour time is up. Bye!\n"
exp_close $spawn_id
exit
}
after [get_user_time_in_milliseconds $env(LOGNAME)] [list byebye $spawn_id]
# rest of expect code goes here.
interact
Expect: exit/finish/close interact on returned output
Here's an example for you. Expect will be controlling this shell script:
#!/bin/sh
PS3="your choice? "
select answer in foo bar baz quit; do
case $answer in
quit) echo "bye bye"; break;;
*) echo "you chose $answer";;
esac
done
echo "out of select loop: hit enter..."
read x
echo "exiting ..."
The expect program is:
#!/usr/bin/env expect
spawn sh test.sh
set keyword "out of select loop"
# signal handlers: ignore these (can't trap SIGKILL)
trap SIG_IGN {HUP INT TERM QUIT}
# interact until a certain pattern is seen
# in the output (-o) of the process
interact {
\003 {
# prevent the user sending SIGINT to the spawned process
puts "don't press Ctrl-C again"
}
-o $keyword {
send_user "you quit\n"
send_user $keyword
return # "return" exits the interact command
}
}
# do other stuff here, for example, hit enter to allow the
# shell script to terminate
expect -re {\.\.\.\s*$}
send_user "... hitting enter ...\n"
send -- \r
expect eof
The expect man page is rough going. You'll be much happier with the Exploring Expect book.
interact doesn't work when expect script contents are piped into
I just come up with a way to do that. See this example:
$ cat foo.exp
if {[catch {
# Close stdin and reopen it as /dev/tty. Then we are
#+ connecting to a tty.
close stdin
open /dev/tty
} err]} {
puts stderr $err
exit 1
}
# Without this, inputed lines will be echo'ed twice.
set stty_init -echo
spawn bash --noprofile --norc
expect -re {bash-[.0-9]+(#|\$) }
interact
exit
$ expect < foo.exp
spawn bash --noprofile --norc
bash-4.2# ptree $$
705 screen -T dtterm -U
24164 bash
26826 expect
26827 bash --noprofile --norc
26830 ptree 26827
bash-4.2# exit
exit
$
To make it more smart we need to check if stdin
is a tty or not at the beginning.
Using two interact in a Expect script
I have resolved the problem:
#!/usr/bin/expect
set timeout -1
set arg1 [lindex $argv 0]
spawn ssh -p 24 my_username@my_linux.domain.com
expect "#"
send "go $arg1 \n"
expect "sername:"
send "my_username\n"
expect "assword:"
send "my_password\n"
expect "#"
interact timeout 5 return
send "\n"
expect "root@my_linux:~#"
send "exit\n exit\n"
interact
Explanation: I added a few lines:
# This prevents commands from timing out (default timeout is 10 seconds).
set timeout -1
# When I type something, the timeout is ignored, but when I'm not typing,
# it waits 5 seconds and then continues.
interact timeout 5 return
send "\n"
expect "root@my_linux:~#"
send "exit\n exit\n"
Expecting the Unexpected in Expect
Try like this:
set timeout 10; # set a reasonable timeout
# expect and send username/password ...
set success 0
set err_msg ""
expect {
"Login success!" {
set success 1
}
eof {
set err_msg $expect_out(buffer)
}
timeout {
expect *
set err_msg $expect_out(buffer)
}
}
if {! $success} {
send_mail $err_msg
exit 1
}
Related Topics
How to Convert Fixed Size Dimension to Unlimited in a Netcdf File
How to Diagnose a Python Process Chewing CPU in Linux
How to Debug a Linux Core Dump Using Vscode
Setup Cron from Morning to Evening Only
How to Create a Real Thread with Clone() on Linux
Linux: How to Put a Load on System Memory
Deploying War in Jboss 7.0.1 Through Commandline
How to Install Python Modules in a Docker Image
Redirecting Apache Logs to Stdout
Sorting with Multiple Keys with Linux Sort Command
Alsa: How to Duplicate a Stream on 2 Outputs and Save System Configs
Mongo Daemon Doesn't Run by Service Mongod Start
Visual Studio Code on Linux Xwindow Forwarding
How to Use File Protocol to Access a Directory on Local System
How to Compile Intel MAC Binaries on Linux