How can I run a script immediately after connecting via SSH?

When you run ssh example.com, the ssh daemon starts a login shell for you, and the login shell reads your ~/.profile (or ~/.bash_profile or ~/.zprofile or ~/.login depending on your login shell). When you specify a command to run remotely (with or without -t), the ssh daemon starts an ordinary shell, so your .profile is not read. Remedy:

ssh example.com -t '. /etc/profile; . ~/.profile; tmux attach'

Most ssh daemons are configured to refuse transmitting environment variables except for LC_*. If the ssh daemon on example.com allows it, you can abuse a custom LC_* variable to start tmux automatically — put this in your ~/.profile:

if [ -n "$LC_tmux_session" ] && tmux has -t "$LC_tmux_session"; then
  exec tmux attach -t "$LC_tmux_session"
elif [ -n "${LC_tmux_session+1}" ] && tmux has; then
  exec tmux attach
fi

then log in with LC_tmux_session= ssh example.com or LC_tmux_session=session_name ssh example.com.

This answer has more information about passing environment variables over ssh.


I previously advised setting PermitUserEnvironment yes and adding an environment variable in your ~/.ssh/environment until Eli Heady chipped in with a better suggestion in the comments below.

Open your .zlogin (bash: .bash_profile etc.) and put the following:

if [[ "$SSH_CONNECTION" != "" && "$MY_SSH_CONNECTION" != "yes" ]]; then
    while true; do
        echo -n "Do you want to attach to a tmux session? [y/n]"
        read yn
        case $yn in
            [Yy]* ) MY_SSH_CONNECTION="yes" tmux attach; break;;
            [Nn]* ) break;;
            * ) echo "Please answer y/n";;
        esac
    done
fi

Inspiration taken from: How do I prompt for input in a Linux shell script?

Note that I've used the .zlogin file but you could use your .zshrc file but I like to keep my dotfiles tidy and it separates it so I can use it on other machines.

Replace the question with something appropriate for yourself and replace MY_SSH_CONNECTION="yes" tmux attach with whatever you wish to run at that point.

Note how the script sets MY_SSH_CONNECTION="yes" before tmux attach to pass it through to tmux as it also will be opening a shell that will access the very same script above and will prevent any recursion.


Myself, I add this to my .bash_profile files:

if [ -z "$STY" ]; then
    reattach() { exec screen -A -D -RR ${1:+"$@"} ; }
fi
if [ -t 0 ]; then
    screen -wipe
    echo 'starting screen... (type Ctrl-C to abort)'
    sleep 5 && reattach
fi

This gives me some time to abort reattaching to or creating a screen session. It won't work on 'ssh system command' formats (which does not call ~/.*profile). A shell function is set up to reattach if I abort.