Use Expect in a Bash script to provide a password to an SSH command

LinuxBashSshExpect

Linux Problem Overview


I'm trying to use expect in a Bash script to provide the SSH password. Providing the password works, but I don't end up in the SSH session as I should. It goes back strait to Bash.

My script:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com'
expect "password"
send "$PWD\n"
EOD
echo "you're out"

The output of my script:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
usr@$myhost.example.com's password: you're out

I would like to have my SSH session and, only when I exit it, to go back to my Bash script.

The reason why I am using Bash before expect is because I have to use a menu. I can choose which unit/device to connect to.

To those who want to reply that I should use SSH keys, please abstain.

Linux Solutions


Solution 1 - Linux

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.

Solution 2 - Linux

The easiest way is to use sshpass. This is available in Ubuntu/Debian repositories and you don't have to deal with integrating expect with Bash.

An example:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh [email protected] ls -l /tmp

The above command can be easily integrated with a Bash script.

Note: Please read the Security Considerations section in man sshpass for a full understanding of the security implications.

Solution 3 - Linux

Add the 'interact' Expect command just before your EOD:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
expect "password"
send -- "$PWD\r"
interact
EOD
echo "you're out"

This should let you interact with the remote machine until you log out. Then you'll be back in Bash.

Solution 4 - Linux

After looking for an answer for the question for months, I finally find a really best solution: writing a simple script.

#!/usr/bin/expect

set timeout 20

set cmd [lrange $argv 1 end]
set password [lindex $argv 0]

eval spawn $cmd
expect "assword:"   # matches both 'Password' and 'password'
send -- "$password\r"; # -- for passwords starting with -, see https://stackoverflow.com/a/21280372/4575793
interact

Put it to /usr/bin/exp, then you can use:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

Done!

Solution 5 - Linux

A simple Expect script:

File Remotelogin.exp
    #!/usr/bin/expect
    set user [lindex $argv 1]
    set ip [lindex $argv 0]
    set password [lindex $argv 2]
    spawn ssh $user@$ip
    expect "password"
    send "$password\r"
    interact

Example:

./Remotelogin.exp <ip> <user name> <password>

Solution 6 - Linux

Also make sure to use

send -- "$PWD\r"

instead, as passwords starting with a dash (-) will fail otherwise.

The above won't interpret a string starting with a dash as an option to the send command.

Solution 7 - Linux

Use the helper tool fd0ssh (from hxtools, source for ubuntu, source for openSUSE, not pmt). It works without having to expect a particular prompt from the ssh program.

It is also "much safer than passing the password on the command line as sshpass does" ( - comment by Charles Duffy).

Solution 8 - Linux

Another way that I found useful to use a small Expect script from a Bash script is as follows.

...
Bash script start
Bash commands
...
expect - <<EOF
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
More Bash commands
...

This works because ...If the string "-" is supplied as a filename, standard input is read instead...

Solution 9 - Linux

sshpass is broken if you try to use it inside a Sublime Text build target, inside a Makefile. Instead of sshpass, you can use passh

With sshpass you would do:

sshpass -p pa$$word ssh user@host

With passh you would do:

passh -p pa$$word ssh user@host

Note: Do not forget to use -o StrictHostKeyChecking=no. Otherwise, the connection will hang on the first time you use it. For example:

passh -p pa$$word ssh -o StrictHostKeyChecking=no user@host

References:

  1. https://stackoverflow.com/questions/33531131/send-command-for-password-doesnt-work-using-expect-script-in-ssh-connection
  2. How can I disable strict host key checking in ssh?
  3. How to disable SSH host key checking
  4. scp without known_hosts check
  5. pam_mount and sshfs with password authentication

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMaxView Question on Stackoverflow
Solution 1 - LinuxPiotr KrólView Answer on Stackoverflow
Solution 2 - LinuxdotnixView Answer on Stackoverflow
Solution 3 - Linuxdr-janView Answer on Stackoverflow
Solution 4 - Linuxdamn_cView Answer on Stackoverflow
Solution 5 - LinuxVijay S BView Answer on Stackoverflow
Solution 6 - LinuxTimmahView Answer on Stackoverflow
Solution 7 - Linuxuser562374View Answer on Stackoverflow
Solution 8 - LinuxJimboView Answer on Stackoverflow
Solution 9 - LinuxuserView Answer on Stackoverflow