Can the expect script continue to execute other command after "interact"? - expect

I am writing a script to run ssh so as to login a remote host, after all the operation is done, I type exit and log off. But I want the script to continue running and write log on the local host. The script is something like:
#!/usr/bin/expect
spwan ssh qwerty#remote_host
expect {
"password:" {
send "123123\r"
}
}
interact;
send "echo $(date) >> login_history.log\r"
But the last command "send ..." always failed with the error message like
"send: spawn id exp4 not open ..."
When I log off from the remote host, can the expect script continue to work as it is running on the local host?

YES, processing can continue after an [interact].
Short answer: change the last {send ...} to {exec date >> login_history.log}
There are several concepts you'll want to understand to achieve the control flow you're after. First, http://www.cotse.com/dlf/man/expect/interact_cmd_desc.htm provides a succinct synopsis and example of intermediate [interact] use.
Second: why did you see the message "... spawn id ... not open ..."? Because the spawn id is not open. The script you wrote said, in effect, "interact, then, after interact is over, send a new command to the ssh process." If you've already logged out, then, of course that id for a defunct process is no longer available.
Third: how do you achieve what you want? I'm unsure what you want. It sounds as though it would be enough for you simply to transform the [send] as I've described above. How does that look to you?

Related

Expect Script - varying sends

I'm working on expect script to call a installer.sh
For a neat installations , it works fine.
But when the installer fails for pre-checks, the order of the send differs and i have no control on the order.
spawn ./Installer.sh
expect "change? (Y/N)"
send "Y\r"
expect "path"
send "$path\r"
expect "Enter selection"
send "1\r"
expect "path"
send "$path
exit 0
After 2nd expect "path", the installer validates internally and proceeds with step3 and continues and finishes.
But if after second expect path , installer pre-checks fails then it exists and prompts for last step ie for the path again.
currently when the script displays after exiting and prompts for 4th, it continues to send the 3rd response which is irrelevant.Does the script does not validate fr the match expect string?
Error :
"No Space. Exiting.
**Path: 1**
cp: cannot create regular file `1': Permission denied
send: spawn id exp5 not open
while executing
"send "path\r""
The shell script exits for various reasons and prompts for last send.
Is there a way to get the last display message expect_out while the session is ongoing and read it and continue based on it.
spawn shellscript
expect_1
send_1
expect_2
send_2
--sh stops and displays exiting...
if expect_out(buffer)=exiting
then
expect_4
send_4
else
expect_3
send_3
expect_4
send_4
exit
The key thing you probably need is the ability to expect several different things at once. Fortunately, this is quite easy to do.
expect {
"change? (Y/N)" {
# Something in here to respond to this case
# This bit is just code, but could be effectively empty too
}
"Exiting" {
# Now we've detected that the installer failed
send_user "oh no!\n"
exit 1
}
}
When using this form, you can restart the current expect from within a handler script by finishing it with exp_continue. As usual, you've got to think careful about what actual patterns to match.

Exporting data from expect script

so i've written a short expect script which logs into a APC Power Distribution Unit interface via telnet and polls the current ampage.
#!/usr/bin/expect
set ip "192.168.0.1"
set username "myusername"
set password "mypassword"
spawn "/bin/bash"
send "telnet $ip\r"
expect "*User Name*"
send "$username\r"
expect "*Password*"
send "$password\r"
expect "*APC*"
send -- "phReading all current\r"
expect "*Success*"
send "quit\r"
expect eof
The script does its job and I see the amps on screen, displayed like this:
apc>phReading all current
E000: Success
1: 7.5 A
apc>quit
What i need to do is 'export' that 7.5 figure, either to a text file or pass it to a bash script as a variable.
Any ideas on how i can do this?
Thank you!
Expect is an extension of TCL, so you have access to all of TCL's constructs.
If I were you I would have the expect script write directly to a file.
See the section "Writing a file" here: http://wiki.tcl.tk/367. It has a simple example for just that. In your case, you will want to open the file for append (a) instead of write (w).
open command documentation at: http://www.tcl.tk/man/tcl8.6/TclCmd/open.htm
Let me know how that works for you.

including conditional statements in expect

I am trying to write a bash script that uses expect to scp a file to remote systems. The expect block that I have so far looks like this
expect -c "
set timeout -1
spawn scp $file user#host:$file
expect "\Are you sure you want to continue connection (yes/no)\"
send -- \"$password\r\"
expect eof
"
The problem is that this handles the case in which the host is not a known host and it asks if I want to continue connecting. I would like to add a an option for the case in which the host is already known and it simply wants the password.
The other issue is that I would like to handle the event in which the password the user entered is not correct. In that case, I would like to have the user reenter the password.
What would be the best way of accomplishing this using bash and expect?
Many thanks in advance!
host is not a known host and it asks if I want to continue connecting
Use: scp -o "StrictHostKeyChecking no" <...>
event in which the password the user entered is not correct
If your script is considered to be interactive, why you are using expect at all? scp can ask and re-ask a password by itself.
Like this:
expect -c "
set timeout -1
spawn scp $file user#host:$file
expect
{Are you sure you want to continue connection (yes/no)} {
send \"yes\r\"
exp_continue
}
{Password: } {
send -- \"$password\r\"
}
}
expect eof
"
The exp_continue command loops back to the containing expect command so that other patterns have a change to be matched.

Writing strings to standard input in bash script

I'm trying to automate a startup of a specific service with bash
When the service is started with init.d (/etc/init.d/openvpn.custom) it is promting for username and then password - and then it connects
The auth-user-pass from-file is not possible with the installed version, and it cannot be upgraded because of dependencies
So i'm trying to write a simple bash scripts that executes the init.d script, sleeps for a bit, inputs the username, returns, sleeping a bit, inputting the password - you'll get the flow.
like http://pastebin.com/qWHX7Di5
I've experimented with echo, but it doesent seem to work
This is for a rather legacy firewall i'm asked to keep connected.
Is this even possible?
I would use expect instead of bash. You can still call it from within bash if you need to do other tasks as well.
In expect, the script would be something like the following (untested):
#!/usr/bin/expect -f
set username "username"
set password "password"
spawn /etc/init.d/openvpn.custom start
expect "Username:"
send "$username\r"
expect "Password:"
send "$password\r"
expect eof
You'd want to change the expect "Username:" & expect "Password:" lines to match the actual login prompts that are output by your init.d script.
See the expect man page for further details.
You can try using a here-doc:
/path/to/init.d << END
$username
$password
END

Problems with terminating connection after running scripts on remote computer using shell script

This is the first time I am writing a shell script. I tried to do as much research as I can to avoid dumb/repetitive question. Please excuse if its repeat/dumb question.
I have a shell script which connects to remote linux machine and runs scripts there. I am using 'expect' to spawn a ssh connection and to issue commands to trigger the job. However, I am having issues while closing the connection after completing the job.
This is my script:
set prompt "(%|#|\\$|%\]) $"
expect -c 'spawn ssh $UN#$STAGE ;
expect password ; send "$PASS \n";
expect -regexp "$PROMPT"; send "./settings.$UN.sh > settings_log.txt \n";
interact'
This script successfully runs the script file for me ($UN and $STAGE parameters are input to the script. I omitted that here for simplicity). However, this leaves me with an open connection.
I tried to close the connection after running the script by using following instead of above
expect -c 'spawn ssh $UN#$STAGE ;
expect password ; send "$PASS \n";
expect -regexp "$PROMPT"; send "./settings.$UN.sh > settings_log.txt \n";
expect -regexp "$PROMPT"; send "exit \n"'
This does close the connection but I noticed that my script file did not run at all. Also the settings_log.txt is not generated at all.
Does this mean, that exit command is aborting the process before its completion? I tried using 'sleep' before exit but it did not help. Is there a better suggested way to terminate the connection when using expect?
Any help is appreciated.
with expect, you terminate your send commands with \r not \n, so
expect -c 'spawn ssh $UN#$STAGE
expect password
send "$PASS\r"
expect -regexp "$PROMPT"
send "./settings.$UN.sh > settings_log.txt\r"
expect -regexp "$PROMPT"
send "exit\r"
expect eof'
Note you can execute remote shell commands and copy files using ssh and scp, directly, without using expect.
For example,
scp ./settings.$UN.sh $UN#$STAGE:settings_log.txt
ssh $UN#$STAGE whatever-you-need-to-execute
The connection will close as soon as soon as whatever-you-need-to-execute completes.
Your outer script seems to be written in csh and sets a variable named "prompt", but your expect script is using a variable called "PROMPT". Try making the two variable names match case.

Resources