Search code examples
linuxsendexpectssh-keysraspberry-pi2

Expect Script - Auto Password


I am trying to make a script which automatically enters the password "root" to copy the ssh-key from A to B. Since ssh-copy does not work on B and also cant be installed i used:

ssh root@$ip mkdir -p .ssh
cat "~/.ssh/id_rsa.pub" | ssh "root@$ip" 'cat >> .ssh/authorized_keys'

To transfer the key. But B delets its storage on reboot. So i have to automate this process. I thought a expect script would be the simplest solution? I am however not very experienced with these.

#!/usr/bin/expect
#31.09.2015

set timeout 30

spawn ssh "root@$ip mkdir -p .ssh"
expect "password:"
send "root\r"
expect "(yes/no)? "
send "yes\r"

spawn cat "~/.ssh/id_rsa.pub" | ssh "root@$ip" 'cat >> .ssh/authorized_keys'
expect "password:"
send "root\r"

interact

It seems to works till the first send. Then however gets stuck and waits for an input? (wrong expect?)


Solution

  • 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