How to use a linux expect script to enter answer a prompt for password
From the comment I got from glenn jackman I was able to figure out that the password prompt was not being matched. I changed my first line to #!/var/bin/expect -d
which provided the necessary debugging output to find out the problem and fix it.
Thanks Glenn!
Hitting a return at password prompt in expect script instead of sending password
In a here-doc, variables like $Username
and $Password
are being expanded by the shell, so they're not seen as literals for Expect
to expand. Since those shell variables aren't set anywhere, they're being expanded to null strings. As a result, it's executing ssh @$FQDN
and sending an empty password.
You need to escape the $
so that Expect
can process them.
You also don't need the set FQDN
line in the Expect script, since you're using the shell variable for that.
#!/usr/bin/bash
FQDN=$1
LogFile=/tmp/Router_${FQDN}.txt
> $LogFile
expect -d <<EOF > $LogFile
set timeout 20
set Username "user"
set Password "***$$$"
spawn ssh \$Username@$FQDN
expect "*assword:"
send "\$Password\r"
expect "#"
send "some command\r"
expect "#"
send "exit\r"
sleep 1
exit
expect eof
EOF
cat $LogFile
Or you could set them as shell variables, just like FQDN
.
#!/usr/bin/bash
FQDN=$1
Username=user
Password="***$$$"
LogFile=/tmp/Router_${FQDN}.txt
> $LogFile
expect -d <<EOF > $LogFile
set timeout 20
spawn ssh $Username@$FQDN
expect "*assword:"
send "$Password\r"
expect "#"
send "some command\r"
expect "#"
send "exit\r"
sleep 1
exit
expect eof
EOF
cat $LogFile
How can I make an expect script prompt for a password?
Use expect's stty
command like this:
# grab the password
stty -echo
send_user -- "Password for $user@$host: "
expect_user -re "(.*)\n"
send_user "\n"
stty echo
set pass $expect_out(1,string)
#... later
send -- "$pass\r"
Note that it's important to call stty -echo
before calling send_user
-- I'm not sure exactly why: I think it's a timing issue.
expect programmers should all read the book: Exploring Expect by Don Libes
Enter sudo password while in expect script
The answer from Donal Fellows is the right way to go, but for completeness here is the interact
solution you were trying for. The command to use is
expect {
"Input 1" { send -- "$env(input1)\r"; exp_continue }
"Input 2" { send -- "$env(input2)\r"; exp_continue }
"password for" { stty -echo
interact -u tty_spawn_id -o "\r" return
stty echo
exp_continue }
eof
}
The problem you have is that you are running expect with the script on stdin, so interact has trouble unless you use -u tty_spawn_id
to get it to work with /dev/tty
and the user. You need to set the echo on/off on this tty explicitly, as sudo will only have done it on the pty between the spawned command and expect.
Expect Script - Auto Password
This is the part you're having trouble with:
spawn ssh "root@$ip mkdir -p .ssh"
expect "password:"
send "root\r"
expect "(yes/no)? "
send "yes\r"
After you send the password you're waiting 30 seconds for (yes/no?
to appear, but it might not appear if you've connected to that machine before. You want to conditionally expect that y/n prompt:
spawn ssh "root@$ip mkdir -p .ssh"
expect {
"(yes/no)? " { send "yes\r"; exp_continue }
"password:" { send "root\r" }
}
expect eof
That form of the expect command allows you to look for multiple strings simultaneously. If the first one seen is "(yes/no)? ", then send "yes" and continue with this expect command. When you see "password:", send the password and let the expect command end.
You might want to change the second spawn command
so a shell can handle the pipeline.
set cmd [format {cat "~/.ssh/id_rsa.pub" | ssh "root@%s" 'cat >> .ssh/authorized_keys'} $ip]
spawn sh -c $cmd
Use Expect in a Bash script to provide a password to an SSH command
Mixing Bash and Expect is not a good way to achieve the desired effect. I'd try to use only Expect:
#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
# Use the correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact
Sample solution for bash could be:
#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com; interact }'
This will wait for Enter and then return to (for a moment) the interactive session.
Related Topics
Check If Opencv Is Compiled with Tbb
Jna Link Issue While Starting Cassandra Rhel 6.5
How to Timeout a Group of Commands in Bash
Flags in Objdump Output of Object File
Filename Last Modification Date Shell in Script
Makefile for Linux Kernel Module
Bash Not Trapping Interrupts During Rsync/Subshell Exec Statements
Xkb: How to Convert a Keycode to Keysym
How to Access the Base Filename of a File You Are Sourcing in Bash
.Bashrc Syntax Error: Unexpected End of File
Direct Control of Hci Device (Bypass Bluetooth Drivers) on Linux
Linux, Gnu Gcc, Ld, Version Scripts and the Elf Binary Format -- How Does It Work
Installing Multiple Versions of R
Qt Version Is Not Properly Installed, Please Run Make Install
Bash Completion for Path in Argument (With Equals Sign Present)
If Adding a Command That Repeats Every 10 Minutes to Crontab, When Does the First Job Run