Ssh, run a command on login, and then Stay Logged In?

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.

-Jonathan

(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"
interact

Solution 1:

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"

:)

Solution 2:

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_custom:

. ~/.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.

Solution 3:

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.

Solution 4:

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.

https://www.freebsd.org/cgi/man.cgi?sshd(8)#LOGIN_PROCESS