I´m getting crazy trying to make this works.
I need to use expect to set a couple passwords. The problem that I have is that I have to run two commands in the same processor.
Here the code
yum install -y expect
secret="price_aws_git_secret.txt"
eval $(ssh-agent)
pass=$(cat $secret)
expect << EOF
spawn ssh-agent ssh-add price_aws_github
expect "Enter passphrase"
send "$pass\r"
spawn git clone git#github/repo.git
expect "Are you sure you want to continue connecting"
send "yes\r"
expect eof
EOF
The first command add into the ssh-agent the ssh key, and the second command the git clone need to be in the same process to get that agent.
Looking documentation and examples I´m not able to see how expect can works with two commands in the same process.
Any suggestion?
Thanks!
Suggestions about using ssh keys better aside, to answer your question. You don't need to interact with two processes at the same time. You need to handle the first one, then start the second:
expect << EOF
spawn ssh-agent ssh-add price_aws_github
expect "Enter passphrase"
send "$pass\r"
# assume this works. if not, there's more work to do
expect eof
close
spawn git clone git#github/repo.git
expect "Are you sure you want to continue connecting"
send "yes\r"
expect eof
EOF
Related
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.
Not sure if this is more of a scripting/unix question or a programming one, but I tried on the unix stackexchange and got no responses, so:
The following expect code seems to work; that is, it appears to enter text in answer to the password prompt. However, the device never actually mounts.
But if I simply enter the command into a shell and type the password in by hand the device mounts successfully.
So I'm curious where the input is actually ending up, as it never seems to 'catch' the password yet doesn't present an error message either? In fact the output looks exactly the same in both instances, but only in the case of running the command and typing the password manually do I see my files appear over the network.
Here is the code:
#!/usr/bin/expect
spawn sudo mount.cifs "//WinPC/My Pictures" /home/LinPC/Desktop/Pictures -o user=Me
expect "Password: " {
set send_slow {1 .1}
send -s "a_password"
}
UPDATE: Got the help I needed to make it work: had to insert 'expect eof' after sending the password so that it doesn't end prematurely. However I now wish to progress to changing it to 'expect_background' so that I can have the same trigger response to issuing multiple mount commands. The following ends prematurely, and 'expect eof' at the end causes an error:
expect_background "Password:" {
send "a_password\r"
expect eof
}
spawn sudo mount.cifs "//WinPC/My Pictures" /home/LinPC/Desktop/Pictures -o user=Me
expect eof
What should it look like?
UPDATE: the following code block illustrates the current problem:
expect_background "Password: " {
send "a_password\r"
expect eof
}
spawn sudo mount.cifs "//WinPC/My Pictures" /home/LinPC/Desktop/Pictures -o user=someone
expect "Password: " {
send "a_password\r"
expect eof
}
#The password prompt gets answered by 'expect' but not 'expect_background'.
#If I delete the last 'expect' and insert 'expect eof' it hangs for a short
#while at the password prompt (around 3 seconds) then exits.
#Why?
Add one more expect statement after sending the password.
send -s "a_password\r"
expect eof
The eof will make the Expect to wait till the end of program.
I need to make a sftp connection with a password and download a file. There is an ip restriction so first of all i should make a ssh connection. I wrote a script but it stucks after connecting with ssh.
Note: i also tried doing it with an expect script but it also didn't work.
#!/usr/local/bin/
ssh test#test1.t.com
lftp sftp://test2:123456#test2.com
get "file.xls"
Edit: You can also see my expect code here.
#!/usr/local/bin/expect -f
expect -c "
spawn ssh test#test1.t.com
expect \"test\#test1\:\~\$\"
spawn sftp test2#test2.com
expect \"*assword:\"
send \"123456\r\"
expect \"sftp\>\"
send \"get file.xls\r\"
expect \"sftp\>\"
exit 1
";
I'm not sure exactly what you're trying to accomplish here. First, I'll address the problems in your expect script. Since your shebang line invokes expect, you don't need to wrap the expect body in a call to expect. That gets rid of all the backslashes. Next, you have 2 spawn calls, which raises questions about you're intent. I'm going to assume that you want to ssh to test1, then grab the file from test2 so the file exists on test1. This assumption changes the 2nd spawn to a plain send command.
#!/usr/local/bin/expect -f
set shell_prompt "test#test1:~$"
set sftp_prompt "sftp>"
spawn ssh test#test1
expect $shell_prompt
send "sftp test2#test2\r"
expect "*assword:"
send "123456\r"
expect $sftp_prompt
send "get file.xls\r"
expect $sftp_prompt
send "exit\r"
expect $shell_prompt
send "exit\r"
expect eof
Now, you can scp the file to your local machine. Let's put those 2 steps into one shell script:
#!/bin/sh
expect <<'EXPECT_SCRIPT'
set shell_prompt "test#test1:~$"
set sftp_prompt "sftp>"
spawn ssh test#test1
expect $shell_prompt
send "sftp test2#test2\r"
expect "*assword:"
send "123456\r"
expect $sftp_prompt
send "get file.xls\r"
expect $sftp_prompt
send "exit\r"
expect $shell_prompt
send "exit\r"
expect eof
EXPECT_SCRIPT
scp test#test1:file.xls .
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 =)
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.