Use Expect in a Bash script to provide a password to an SSH command
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>
Related videos on Youtube
Max
Analytics consultant available for hire. More info: https://maxcorbeau.com
Updated on November 23, 2021Comments
-
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 over 13 yearsplease see first line: To those who want to reply that I should use SSH keys please abstain
-
Tim Post over 13 yearsI 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 over 5 yearsI would try to use kermit in this case. It has a very robust scripting language columbia.edu/kermit/skermit.html#scripts
-
Cadoiz over 2 years
-
-
Max over 13 yearsit 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 over 13 yearsThis 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 over 13 yearsThe same way I send the password when prompted, I would like to send system commands once logged in.
-
Piotr Król over 13 yearsSamlple 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 over 12 yearsThis 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 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 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 about 11 yearsIt goes in and goes back out immediately. "you're out" is printed.
-
Emmanuel about 11 yearsI've replaced "interact" and "EOD" with "expect eof" and it worked for me. This is on a Mac.
-
erikbstack over 9 yearsI don't know if it's a good solution, but it certainly simplifies a lot. Thanks
-
Charles Duffy almost 9 yearsVery 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 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 inman sshpass
where a whole section on Security Considerations is explained. Added this to answer, Thanks. -
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 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 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 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 about 8 yearsFor 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 over 6 yearsNone of the answers on this page worked for me but @Emmanuel's suggestion to use
expect eof
solved the issue. -
pynexj about 6 yearstake a look at sexpect. you can write expect scripts with bash only.
-
Tino almost 6 yearsYou do not need the
-
here, asexpect
reads fromstdin
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 likeexpect -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 fromstdin
. -
Tino almost 6 yearsRemove the
'
fromusr@$myhost.example.com'
and it should work. And perhaps you need to replace\n
with\r
, but YMMV -
Timo over 3 yearsGreat also is for scp with the two arguments. Of course, ssh also with 2 arguments possible.
-
Kvothe over 3 yearsI 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 almost 3 yearsThis is useless for mounting a folder via ssh
-
i_want_more_edits over 2 yearsPlease consider adding this fix as some passwords might not work else
-
i_want_more_edits over 2 years
-
MaThMaX over 2 yearsAfter 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 about 2 yearsQuestions: 1) can 'some-pattern' use wildcards? 2) What is 'your-command-here' is something like 'git push', should it be quoted?
-
Josef Klimuk almost 2 yearsDoes it work only for one command?