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

429,239

Solution 1

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

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

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

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

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>
Share:
429,239

Related videos on Youtube

Max
Author by

Max

Analytics consultant available for hire. More info: https://maxcorbeau.com

Updated on November 23, 2021

Comments

  • Max
    Max over 2 years

    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.

    • Max
      Max over 13 years
      please see first line: To those who want to reply that I should use SSH keys please abstain
    • Tim Post
      Tim Post over 13 years
      I would edit your first line to be a little friendlier. You might consider something like "Due to constraints, I simply can not use SSH keys, I must find a way to get it working with expect". You should expect that people might be naturally curious why you aren't using keys, and are just trying to be helpful :) @Ignacio didn't suggest that you use them, he was simply confirming it as a constraint and not an oversight.
    • f3xy
      f3xy over 5 years
      I would try to use kermit in this case. It has a very robust scripting language columbia.edu/kermit/skermit.html#scripts
    • Cadoiz
      Cadoiz over 2 years
  • Max
    Max over 13 years
    it works great, thanks. What if I want to type in command once I'm logged in via SSH, what do I need to do?
  • Piotr Król
    Piotr Król over 13 years
    This script should return ineractive shell with logged in user. I dont understand question. If you absolutely want to use the same script in bash look at the edited entry.
  • Max
    Max over 13 years
    The same way I send the password when prompted, I would like to send system commands once logged in.
  • Piotr Król
    Piotr Król over 13 years
    Samlple code was added to post above. Of course this will work until my_commandX don't change returned prompt, if this happens prompt variable should be changed.
  • JP Illanes
    JP Illanes over 12 years
    This is great! It's a bit hard to make it run (at least in ubuntu server) but works smoothly! The config we made: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port [email protected] & THANKS!
  • Richard
    Richard over 11 years
    @pietrushnic can you explain a bit why use "interact -o -nobuffer -re $prompt return", instead of "expect $prompt"? the latter one looks more commonly used..
  • Piotr Król
    Piotr Król over 11 years
    @Richard best explanation was provided on wiki.tcl.tk/3914, "The major difference is that interact sets up a background matching event loop. expect blocks foreground processing (and ignores user input) during it's matching event loop. interact also has a set of switches that allow programmers to spawn two sessions and connect their ptys, thus letting them drive each other."
  • Emmanuel
    Emmanuel about 11 years
    It goes in and goes back out immediately. "you're out" is printed.
  • Emmanuel
    Emmanuel about 11 years
    I've replaced "interact" and "EOD" with "expect eof" and it worked for me. This is on a Mac.
  • erikbstack
    erikbstack over 9 years
    I don't know if it's a good solution, but it certainly simplifies a lot. Thanks
  • Charles Duffy
    Charles Duffy almost 9 years
    Very dangerous from a security perspective -- command-line arguments can be read by any other process on the system. It's possible to overwrite them, and hopefully sshpass does that, but even then there's a period while it's still starting up before it's able to do that when the password is available for any/every process to see.
  • dotnix
    dotnix almost 9 years
    @CharlesDuffy Of course, you are correct. sshpass is used in a scenario where you have simple test scripts that execute in a local network environment where security is not the top concern. In fact, there is a section in man sshpass where a whole section on Security Considerations is explained. Added this to answer, Thanks.
  • m3nda
    m3nda almost 9 years
    @erikb85 Usually, a package does all the dirty stuff for you, but, in all cases, these scripts are built just for that usage, then would be BETTER than add your own stuff. This comment is about don't reinvent the wheel. Deal with hard stuff only if no people has dealed yet with it. sshpass it's a good function.
  • erikbstack
    erikbstack almost 9 years
    @erm3nda Your comment applies to use OpenSSL instead of implenting your own SSL library. It might be nasty in the details so let experts deal with it. But sshpass is not just a very small tool, it's doing something inherently wrong. You should not do it this way. Use RSA key files instead if you don't want to use passwords. It's not about the nasty details, but about it's inherent problem of writing clear text passwords in a line of bash. Avoid such tools! (Of course I'm also use it because I'm lazy, but you really shouldn't actually)
  • m3nda
    m3nda almost 9 years
    @erikb85 I actually use keys the the most ssh connections i made, but sshpass has make the work instead of have to manually enter that data. There are so many scenarios.
  • Piotr Król
    Piotr Król over 8 years
    @Abdull mainly because solution is cleaner and more readable. Using expect from bash does not add anything to solution. Also I meant more code sample provided in question and the way it mix expect and bash, then general rule of not mixing those two scripting languages.
  • Ron Burk
    Ron Burk about 8 years
    For completeness, I mention that "man sshpass" delivers suitable security warnings to the prospective user, points out that "-p" is the least secure way to use it, and offers the "-e" option for taking the password via environment variable, which at least keeps it off the command line.
  • moertel
    moertel over 6 years
    None of the answers on this page worked for me but @Emmanuel's suggestion to use expect eof solved the issue.
  • pynexj
    pynexj about 6 years
    take a look at sexpect. you can write expect scripts with bash only.
  • Tino
    Tino almost 6 years
    You do not need the - here, as expect reads from stdin by default if you invoke it without argument. However it is useful if you want to run it interactively without command prompt (expect vs. expect -) or in case you do something like expect -f "$@" where the first argument shall be a file, even if it looks like an option (starts with -). In that case, if $1 (the file given) is - this reads from stdin.
  • Tino
    Tino almost 6 years
    Remove the ' from usr@$myhost.example.com' and it should work. And perhaps you need to replace \n with \r, but YMMV
  • Timo
    Timo over 3 years
    Great also is for scp with the two arguments. Of course, ssh also with 2 arguments possible.
  • Kvothe
    Kvothe over 3 years
    I tried the above and it worked perfectly when I ran the script from the terminal. However, when I run the script from nautilus it does not work. Any idea what could be going wrong and how to fix it?
  • Peter Kionga-Kamau
    Peter Kionga-Kamau almost 3 years
    This is useless for mounting a folder via ssh
  • i_want_more_edits
    i_want_more_edits over 2 years
    Please consider adding this fix as some passwords might not work else
  • i_want_more_edits
    i_want_more_edits over 2 years
  • MaThMaX
    MaThMaX over 2 years
    After I followed @Emmanuel's suggestion to use expect eof, I was able to login to the server. However I cannot type any cmd, it's not interactive session and logs out automatically soon
  • Erwann
    Erwann about 2 years
    Questions: 1) can 'some-pattern' use wildcards? 2) What is 'your-command-here' is something like 'git push', should it be quoted?
  • Josef Klimuk
    Josef Klimuk almost 2 years
    Does it work only for one command?