I tried this with expect, but it didn't work: it closed the connection at the end.

Can we run a script via ssh which will log into remote machines, run a command, and not disconnect?

So ssh in a machine, cd to such and such a directory, and then run a command, and stay logged in.


(expect I used)

#!/usr/bin/expect -f
set password [lrange $argv 0 0]
spawn ssh root@marlboro "cd /tmp; ls -altr | tail"
expect "?assword:*"
send -- "$password\r"
send -- "\r"
  • 9
    Is it just me or are you "automating" password authentication this way, instead of using pubkeys or other sane method? – grawity Oct 29 '09 at 19:22

Add a ; /bin/bash to the end of your command line on the remote side? That is:

spawn ssh -t root@marlboro "cd /tmp; ls -altr | tail; /bin/bash -i"

Even better, change root's .bashrc to be something like this:

PROMPT_COMMAND="cd /tmp && ls -altr | tail ; unset PROMPT_COMMAND"


  • 2
    You may want to add -i to that bash. – Teddy Oct 29 '09 at 19:18
  • Yeh, I suppose :) – Bill Weiss Oct 29 '09 at 19:34
  • When I do that, tab completion breaks in the new shell (even with "-i") -- any idea why / how to fix? – Coderer May 28 '10 at 19:34
  • 1
    I tested my new answer here, it works great. A little rough, but it works. – Bill Weiss May 28 '10 at 21:47
  • 7
    Try ssh -t to allocate a pty. – Dennis Williamson Dec 11 '10 at 19:31

If you are ok with doing this in Python, pexpect has an example that does almost exactly what you are asking for:

import pexpect
child = pexpect.spawn ('ftp ftp.openbsd.org')
child.expect ('Name .*: ')
child.sendline ('anonymous')
child.expect ('Password:')
child.sendline ('noah@example.com')
child.expect ('ftp> ')
child.sendline ('ls /pub/OpenBSD/')
child.expect ('ftp> ')
print child.before   # Print the result of the ls command.
child.interact()     # Give control of the child to the user.

To do this with ssh instead of ftp, you'd want code similar to the following (the example files in pexpect have much more details and info, but here are the basics):

import pexpect
child = pexpect.spawn ('ssh root@marlboro')
child.expect ('Password:')
child.sendline ('password')
child.expect ('prompt# ')
child.sendline ('cd /tmp')
child.expect ('prompt# ')
child.sendline ('ls -altr | tail')
child.expect ('prompt# ')
print child.before, child.after   # Print the result of the ls command.
child.interact()     # Give control of the child to the user.

Don't get me wrong, I LOVE expect (especially autoexpect), but python is just soooo much easier for me to grok.

  • I too am transitioning from expect to pexpect. python is now much more ubiquitous. – J. M. Becker Oct 27 '11 at 18:50

The probably easiest and cleanest way to ssh into a server, spawn an interactive shell and run commands inside that shell is to create a custom rc file for bash.

In your custom bashrc file on the server, first source the default file and then add your custom commands, e.g.


. ~/.bashrc
cd dir/
workon virtualenvproject

You can then start your SSH session like this:

$ ssh -t server "/bin/bash --rcfile ~/.bashrc_custom -i"

The -t option forces a pseudo-tty allocation, so that things like tab-completion work.

The --rcfile option specifies which rcfile to load instead of the default one. Important: you must put "double-dash arguments" on the command line before the single-character options in order to be recognized.

The -i argument to /bin/bash is there to invoke an interactive shell.

  • actually not. What to do if I want to run different commands for each connection? – Eugen Konkov Mar 1 '16 at 8:37

If anybody wants information on what is happening in the background, you should take a look at the sshd manual:

When a user successfully logs in, sshd does the following:

  1. If the login is on a tty, and no command has been specified, prints last login time and /etc/motd (unless prevented in the configuration file or by ~/.hushlogin; see the FILES section).
  2. If the login is on a tty, records login time.
  3. Checks /etc/nologin and /var/run/nologin; if one exists, it prints the contents and quits (unless root).
  4. Changes to run with normal user privileges.
  5. Sets up basic environment.
  6. Reads the file ~/.ssh/environment, if it exists, and users are allowed to change their environment. See the PermitUserEnvironment option in sshd_config(5).
  7. Changes to user's home directory.
  8. If ~/.ssh/rc exists, runs it; else if /etc/ssh/sshrc exists, runs it; otherwise runs xauth(1). The ``rc'' files are given the X11 authentication protocol and cookie in standard input. See SSHRC, below.
  9. Runs user's shell or command.



You should generally avoid using ssh in this kind of way as it defeats it's purpose.
Do an

ssh-add -l | grep "file_of_your_rsa_priv_key_here"

to see if your key is listed in the ssh active session pool or else add it yourself (with ssh-add).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.