expect script answering questions interactively - expect

I want to create a script which i will use to generate some reports, but to do that i have to answer few questions, which being asked by other script i run (already located in destination server in /tmp)
The answers can be yes, no, for some questions i need to select 1,2 or 3, i some cases i need "Press [Enter] to continue:"...
So my questions how to do it in the best way?
How do i ssh to destination servers (are located in file on source jump server and to which i have passworless connection to from jump server) like i do it in bash?
#!/bin/bash
while read LINE ; do
ssh - $LINE <<"EOF"....
This is my script as of now, the order of the answers is:
yes/yes/yes/ENTER/2/3/1/no/no/yes
#!/usr/bin/expect -f
spawn ssh ???????
send -- "/tmp/sort_hpux.sh\r"
expect "Would you like to run the data collector now? [y,n] (y)"
send -- "y\r"
expect "Directory '/var/VRTS/VRTSspt' does not exist. Do you want to create it? [y,n,q] (y)"
send -- "y\r"
expect "Press [Return] to indicate your acceptance of the terms and conditions as indicated in the /tmp/./sort/advanced/terms.txt file, or q to decline: (y)"
send -- "y\r"
expect "Press [Return] to continue:"
send -- "\r"
expect "Choose your option: [1-2,q] (1)"
send -- "2\r"
expect "Choose your option (separate multiple selections with commas): [1-5,b,q] (1,2,3)"
send -- "3\r"
expect "Choose your option: [1-3,b,q] (1)"
send -- "1\r"
expect "Do you want to create a sanitized report with no hostnames and IP addresses? [y,n,q] (n)"
send -- "n\r"
expect "Would you like to send SORT Data collector session logs to Veritas to help improve SORT Data collector in future? [y,n,q] (y)"
send -- "n\r"
expect "Your tasks are completed. Would you like to exit the data collector? [y,n,q] (y)"
send -- "y\r"
expect eof

Would this work? Often the best expect choice is to not use it at all.
printf "%s\n" yes yes yes "" 2 3 1 no no yes \
| ssh host /tmp/sort_hpux.sh

Related

How can I login to a program in Linux with a .sh script?

I'm sure that this is somewhere on stack overflow, but I've been researching this for hours and none of the answers work.
I need to answer prompts in a .sh script to log in to different accounts automatically.
My script will not answer the prompts automatically.
#!/bin/bash
program9000 login
That part works fine.
Then i get a series of prompts and cannot figure out how to get the .sh script to reply automatically. I will be replying to these 4 prompts the same way every time.
Would you like to enter a new key?
I would like to reply
y
How would you like to authenticate?
1. enter password
2. do something else
3. do something else
q. Quit
I would like to reply
1
Enter your password, please
I would like to reply
mypassword
Enter your Domain name, please
I would like to reply
https://mydomain.mine.com
Please note that I am not writing the prompts, they are coming from program9000. I just want to reply with the same 4 responses every time.
The following have not worked in my .sh script
yes
echo
send
What should the following lines of my script look like?
Here are some things that don't work
#!/bin/bash
program9000 login
send "y"
send "1"
send "fakepassword"
send "https://fakedomain.com"
#!/bin/bash
program9000 login
{ send -- "y" }
{ send -- "1" }
{ send -- "fakepassword"
{ send -- "https://fakedomain.com" }
You can use expect language, available almost with every *nix distributive
You can send multiline "answerfile" or string to your program using redirection
program9000 login <<< "
y
1
fakepassword
https://fakedomain.com"
As others have already mentioned, use expect.
apt show expect
...
Description: Automates interactive applications
Expect is a tool for automating interactive applications according to a script.
Following the script, Expect knows what can be expected from a program and what
the correct response should be.
...
See the expect man page here
To install it on Debian or it's derivatives:
apt install expect
You can use expect.
My English is terrible.So I write a example.
fakeprogram9000.sh
assert_var()
{
if [ $1 != $2 ]; then
echo err; exit 1
fi
}
read -p 'Would you like to enter a new key?' var1
assert_var $var1 'y'
read -p 'How would you like to authenticate?' var1
assert_var $var1 '1'
read -p 'Enter your password, please' var1
assert_var $var1 'fakepassword'
read -p 'Enter your Domain name, please' var1
assert_var $var1 'https://fakedomain.com'
echo success
example.sh
#!/bin/bash
expect<<EOF
spawn bash ./fakeprogram9000.sh login
expect "Would you like to enter a new key?" {send "y\r"}
expect "How would you like to authenticate?" {send "1\r"}
expect "Enter your password, please" {send "fakepassword\r"}
expect "Enter your Domain name, please" {send "https://fakedomain.com\r"}
expect eof
EOF

Bash scripting with expect. Set parameters to multiple test boards

I'm working on a small project for school. I'm using 15 or so tuners to emulate a Cell network. I'm by no means well versed in scripting yet. I'm an EE who usually googles until I have some frankencode capable of my purposes.
The goal is the set up all the modules quickly so I thought to automate the process with a script. This requires ssh, and so far I have to manually type in the password each time. This morning I set up a basic test with both Expect and sshpass. In either case I can correctly log in, but not give instructions to the remote machine.
I was reading that sshpass has difficulty with sending remote instruction, correct me if I'm wrong.
/usr/bin/expect << EOF
spawn ssh root#<IP>
expect "(yes/no)?" #Are you sure you want to connect nonsense
send "yes\r"
expect "password"
send "$pass\r"
I tried a few things here to get the device to receive instruction
interact
cat /pathto/config.txt
#or
send "cat /pathto/config.txt
#the real goal is to send this instruction
sqlite3 /database.db "update table set param=X"
EOF
You might as well make it an expect script, not a shell script
#!/usr/bin/expect -f
and then pass the IP address to the script as a command line argument
expect myloginscript.exp 128.0.0.1 the_password
In the expect script, you'll grab that IP address from the arguments list
set ip [lindex $argv 0]
set pass [lindex $argv 1]
(Putting the password on the command line is not good security practice. You can research better methods of passing the password to your expect script.)
To use ssh, you'll be asked "are you sure" only the first time to connect, so let's make that conditional. That is done by letting the expect command wait for several patterns:
spawn ssh root#$ip
expect {
"(yes/no)?" {
send "yes\r"
# continue to wait for the password prompt
exp_continue
}
"password" {
send "$pass\r"
}
}
Once that is sent, you should expect to see your shell prompt. The pattern for this is up to your own configuration but it typically ends with a hash and a space.
expect -re {# $}
Now you can automate the rest of the commands:
send "cat /pathto/config.txt\r"
expect -re {# $}
# note the quoting
send "sqlite3 /database.db \"update table set param='X'\"\r"
expect -re {# $}
At this point, you'll want to log off:
send "exit\r"
expect eof
On the other hand, if you set up ssh private key authentication (see ssh-keygen and ssh-copy-id), you can just do this:
ssh root#IP sqlite3 /database.db "update table set param='$X'"
and not have to get into expect at all.

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.

Handle multiple statements in an Expect script

I am new to Expect scripting.
I wrote an Expect script for ssh in a Linux machine, where I am facing a problem in ssh'ing to different Linux machines. Below I have copied the script.
!/usr/local/bin/expect
set LinuxMachine [lindex $argv 0]
spawn ssh root#$LinuxMachine
expect "root#$LinuxMachine's password:"
send "root123\n"
expect "[root#Client_FC12_172_85 ~]#"
send "ls"
interact
When I supply 10.213.172.85 from command line the expect in the 4th line, it reads as "root#10.213.172.85's password:" and logs in successfully
But some Linux will expect
The authenticity of host '10.213.172.108 (10.213.172.108)' can't be established.
RSA key fingerprint is da:d0:a0:e1:d8:7a:23:8b:c7:d8:40:8c:b2:b2:9b:95.
Are you sure you want to continue connecting (yes/no)
In this case the script will not work.
How can I have two Expect statements in one Expect command?
You can use exp_continue in such a case:
expect {
"Are you sure you want to continue connecting (yes/no)" {
send "yes\r"
exp_continue
}
"root#$LinuxMachine's password:" {
send "root123\r"
expect "[root#Client_FC12_172_85 ~]#"
send "ls\r"
interact
}
}
In the above, the Expect block waits for either the yes/no question OR the prompt for password. If the latter, it moves on with providing password, expecting prompt, sending ls command and giving control back.
If the former, it will answer 'yes' and repeat the expect block, ready to find the prompt for a password (or even the yes/no question again, for that matter - not that you will need that).
I would also include some timeouts with meaningful messages in case some expect option does not match as expected, but the above should work.
As a side comment, you don't want to set a root password in a script... I recommend using ssh key authentication.
We like to call it "long log in". There are ssh options that don't check the host keys:
send -- "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no username#host\n"
expect {
"Password" {
send -- "$passwd\n"
}
Part of the Bash script that calls on the expect sets the password:
echo -n "Enter LDAP password: "
read -s passwd
echo

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