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"
  • 10
    Is it just me or are you "automating" password authentication this way, instead of using pubkeys or other sane method? Oct 29, 2009 at 19:22

7 Answers 7


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, 2009 at 19:18
  • Yeh, I suppose :)
    – Bill Weiss
    Oct 29, 2009 at 19:34
  • 1
    I tested my new answer here, it works great. A little rough, but it works.
    – Bill Weiss
    May 28, 2010 at 21:47
  • 9
    Try ssh -t to allocate a pty. Dec 11, 2010 at 19:31
  • 1
    This also works for vagrant ssh. It enables you to ssh to vagrant, run commands and stay logged in not exiting, ex. vagrant ssh -- -t "whatever_commands; /bin/bash -i". Apr 1, 2016 at 22:26

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? Mar 1, 2016 at 8:37

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 ('[email protected]')
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. Oct 27, 2011 at 18:50

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.



If you like tmux:

ssh -t user@host "cd /tmp; tmux a || tmux"

After logging in, this always runs cd /tmp on the remote host. Then it tries to attach to an already running tmux session where you can continue to work where you left off after the last ssh disconnection (simulate this by typing sequentially Enter ~ .) or tmux detachment (Ctrl+b d), and if there is no running tmux session, then it will start a new tmux session, which will also keep you logged in using the shell configured for that user.


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).


Solutions here partially worked for me, but not for an ongoing process. Adding ; bash was the key to return to bash after (thanks to this solution).

# Starts SSH, runs the script, and stays logged in after exiting script.
ssh [email protected] -t "./runUntilCtrlC.sh; bash"

# Troubleshooting:
# Check the remote shell is bash with `echo "$SHELL"`.
# For a bonus, make it an alias if you do it all the time
# Add to bottom of your local profile (~/.zprofile or ~/.bash_profile)
alias runFoo='ssh [email protected] -t "./run.sh; bash"'

# save and quit editing

# Load it immediately, instead of waiting for reboot.
source ~/.zprofile # or ~/.bash_profile or whatever

# Then use the alias

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .