Bash Scripting, send "logout" command being skipped during ssh session - bash

Essentially I connect to remote host, authenticate, run command, logout. However logout command is being skipped.
/usr/bin/expect << EOD
spawn ssh $_host
expect "Password: ";
send "$_pass\r";
expect "$_host>";
send "sh arp | inc $_host2\r";
expect "$_host>";
send "logout\r";
EOD
echo "blah blah"
What i get is my expected output from arp command however, blah blah will be entered into the terminal of the remote host. It seems the logout command is being skipped, somewhat new to bash scripting but it seems that expect doesn't instantly see "$_host>" when executing and skips it? Appreciate any feedback.

Don't use expect here at all. Even if you must get the password from a variable, using sshpass for the purpose will avoid mixing two separate languages (bash and TCL).
SSHPASS="$_pass" sshpass -e "$_host" "sh arp | inc $_host2"

I believe the \r ( carrige return ) should be \n ( enter / new line ) ?
send "logout\r"; -> send "logout\n";
If that will help - I would replace it in the entire script ..
Suggesting:
/usr/bin/expect << EOD
match_max 1000000
spawn ssh $_host
expect "Password: ";
send "$_pass\n";
expect "$_host>";
send "sh arp | inc $_host2\n";
expect "$_host>";
send "logout\n";
EOD
echo "blah blah"

Related

Expect script does not work with multiple password requests

I'm trying to execute a perl script to connect to linux hosts generate a snap and then I need to SCP this snap to my local server. So I have to put password 2 times 1 - to login on the servers and 2 - to SCP the file previously generated.
The problem is, my expect script is only working for the first password, would anyone have any idea?
[linuxserver]$ ./mul.sh
spawn perl perlscript.pl
Cleaning up /tmp/logs
Getting logs from server 9.x.x.x using snap
Password: <------ THIS ITERATION WORKS FINE WITH EXPECT
Password: <------ THE 2nd ITERATION DOES NOT WORK AND I HAVE TO ADD THE PASSWORD MANUALLY
[linuxserver]$
export PASSWORD='mypassword'
/usr/bin/expect -c '
spawn perl perlscript.pl
expect {
-nocase "*assword*" {
send "$env(PASSWORD)\r"
exp_continue
}
expect -c "
expect "*assword*"
send \$env(PASSWORD)\r
interact"
}
interact
'
First, use a quoted heredoc when putting an expect script inside a bash script, it reduces quoting hell significantly.
It seems you need to enter the passwords and then just wait for the perl program to end:
put multiple patterns in the same expect command
use the special eof pattern to expect the end of the spawned program.
/usr/bin/expect <<'END_EXPECT'
set timeout -1
spawn perl perlscript.pl
expect {
-nocase "*assword*" {
send "$env(PASSWORD)\r"
exp_continue
}
eof
}
END_EXPECT

Why '\n'('\r') does not work in my expect script

I want to input y+enter to reply the question while executing copy tftp:something.
The script will send y, but \n does not work. It will stay (y/n)y and keep there without exiting or doing something else. I have tried \r, and the result was the same. Does anyone know the reason?
#!bin/bash
expect -c "
set timeout -1
spawn telnet x.x.x.x
expect \"username\"
send \"user\n\"
expect \"password\"
send \"pw\n\"
expect \"model\"
send \"copy tftp:something\n\"
expect \"(y/n)\"
send \"y\n\"
expect eof
"
exit 0
I prefer using \r to "hit enter".
Second, your entire bash script is expect, so remove the outer bash layer.
#!/usr/bin/expect -f
set timeout -1
spawn telnet x.x.x.x
expect "username"
send "user\r"
expect "password"
send "pw\r"
expect "model"
send "copy tftp:something\r"
expect "(y/n)"
send "y\r"
expect eof
If you have more logic in the bash part, to avoid quoting hell use a heredoc:
#!/bin/bash
expect <<'END_EXPECT'
set timeout -1
spawn telnet x.x.x.x
expect "username"
send "user\r"
expect "password"
send "pw\r"
expect "model"
send "copy tftp:something\r"
expect "(y/n)"
send "y\r"
expect eof
END_EXPECT
exit 0

expect telnet to multiple cisco devices and execute show run

I have the following scripts which is supposed to pull the IP address from a file device-list.txt and then telnet to the device, login and execute a show run. The script logs in to the device successfully, but gives me an error after that. Any ideas where im going wrong?
for device in `cat device-list.txt`; do ./test4 $device;done
cat test4
#!/usr/bin/expect -f
set hostname [lindex $argv 0]
set user myusername
set pass mypassword
set timeout 10
log_file -a ~/results.log
send_user "\n"
send_user ">>>>> Working on $hostname # [exec date] <<<<<\n"
send_user "\n"
spawn telnet $hostname
expect "Username:"
send "$user\n"
expect "Password:"
send "$pass\n"
expect "#"
send “term len 0\n”
send “show running-config\n”
expect “end\r”
send “\n”
send “exit\n”
User Access Verification
Username: myusername
Password:
ROUTER#usage: send [args] string
while executing
"send “term len 0\n”"
(file "./test4" line 26)
Your problem is due to incorrect double quotes. You have to use double quotes ", not smart quotes “
send “term len 0\n” ; # Wrong
send "term len 0\r"; # Correct
Note :
Basically, Expect will work with two feasible commands such as send and expect. If send is used, then it is mandatory to have expect (in most of the cases) afterwards. (while the vice-versa is not required to be mandatory)
This is because without that we will be missing out what is happening in the spawned process as Expect will assume that you simply need to send one string value and not expecting anything else from the session.
So, we recommend to use expect after each send, to make sure our commands actually sent to the spawned process. (You have not used expect after sending some commands such as term len 0\r). Also, use \r instead of \n.

How to automate the process with expect tool?

I want to automate a process with expect :
1.login with a common user in ssh
2.su to root
3.make diretory /home/test
set user xxxx
set host yyyy
set password1 pass1
set password2 pass2
set timeout 60
spawn ssh $user#$host
expect "*assword:*"
send "$password1\r"
spawn su
expect "*assword:*"
send "$password2\r"
send "mkdir /home/test"
close
How to fix the codes to automate my process?
Basically, expect will work with two feasible commands such as send and expect. In this case, if send is used, then it is mandatory to have expect (in most of the cases) afterwards. (while the vice-versa is not required to be mandatory)
This is because without that we will be missing out what is happening in the spawned process as expect will assume that you simply need to send one string value and not expecting anything else from the session, making the script exits and causing the failure.
Apart from the commands being missed, I see one issue with su command. I hope your intention is to create directory with su command execution in the remote host, not in local. So, assuming that, you just have to send the command as su to the server. Your current code will spawn su in the local machine.
#!/usr/bin/expect
set host xxx.xxx.xxx.xxx
set user dinesh
set loginpwd welcome
set adminpwd root
set timeout 60
set prompt "#|>|\\\$"; # We escaped the `$` symbol with backslash to match literal '$'
spawn ssh $user#$host
expect -nocase "password:"
send "$loginpwd\r"
expect -re $prompt
send "su\r"
expect -nocase "password:"
send "$adminpwd\r"
expect -re $prompt
send "mkdir /home/test\r"
expect -re $prompt
send "logout\r"
expect eof
eof will wait for the closure of the ssh session.

Script to get info from multiple servers

I want to collect info from a number of servers whether their grub.conf contains the "elevator" parameter or not.
Now, password-less key authentication is something I can not do as of now. I am okay with specifying password in script.
Can someone please help me achieving this?
This is what I did:
#!/bin/bash
GRUB="/etc/grub.conf"
_pair="$(</home/wadhwaso/login.txt)"
Server_info="/tmp/server_info"
for e in $_pair
do
# extract user and ips for each $e in $_pair
IFS='#'
set -- $e
_user="$1"
_ip="$2"
sleep 2
echo "Connecting to server '${_ip}' via SSH..."
ssh ${_user}#${_ip} "sudo grep -q "elevator=noop" "$GRUB" >/dev/null"
if [ $? -eq 0 ]; then
echo "Present on ${_ip}" | tee -a "${Server_info}"
else
echo "not present on ${_ip}" | tee -a "${Server_info}"
fi
done
I don't want to give password every time, and as password-less authentication is not present in my environment and will not be possible, I have to pass the password in script itself which really doesn't bother me, I can do that. I know it could be done through expect but I messed everything every time I tried using it.
I tried using expect the way it was told in 1st answer but I failed.
The "expect" tool sounds perfect for what you need: http://expect.sourceforge.net/
To install expect (on ubuntu, for example), do:
sudo apt-get install expect
Here's a code snippet showing you how to use expect as part of a bash script:
#!/bin/bash
IP="111.111.11.1"
login="root"
password="some_password"
dest_dir="/etc/"
expect_sh=$(expect -c "
spawn ssh $login#$IP
expect \"password:\"
send \"$password\r\"
expect \"#\"
send \"cd $dest_dir\r\"
expect \"#\"
send \"chmod +x $server_side_script"
expect \"#\"
send \"./$server_side_script\r\"
expect \"#\"
send \"cd /lib\r\"
send \"cat $file_count\r\"
expect \"#\"
send \"exit\r\"
")
echo "$expect_sh"
Alternatively, you can put the logic in a separate expect script for neater syntax and source it from your bash script:
#!/usr/bin/expect
set login "root"
set addr "111.111.1.1"
set pw "root"
spawn ssh $login#$addr
expect "$login#$addr\'s password:"
send "$pw\r"
expect "#"
send "cd /etc\r"
# Then other things you need to do
As for the "3rd thing" with RSA key fingerprint: SSH will warn you if connecting to a host you haven't seen before (because of possibility of man-in-the-middle attacks), theoretically you should verify that the fingerprint matches what you anticipate it to be to verify that the host is who the host claims to be.
Hope this helps =)

Resources