5

I want tmux to start on ssh login.

The typical advice is to add this to ~/.bashrc:

if [ -z "$TMUX" ] && [ -n "$SSH_TTY" ] && [[ $- =~ i ]]; then
  tmux attach-session -t mysession 2>/dev/null || tmux new-session -s mysession
fi

But when I log in, I get this error from tmux:

lost server

...And then I'm in bash as usual.


UPDATE

When I add a sleep:

if [ -z "$TMUX" ] && [ -n "$SSH_TTY" ] && [[ $- =~ i ]]; then
  tmux attach-session -t mysession 2>/dev/null || $(sleep 1 && tmux new-session -s mysession)
fi

...then it works. Strange! What is the reason?

lonix
  • 1,639
  • 18
  • 32
  • What options do you pass to `ssh` when logging in? You must allocate a tty with `-t`. Also, you must avoid starting `tmux` if you're already in a `tmux` session (note that running `tmux` starts a new shell, which parses `~/.bashrc`). – Kusalananda Nov 17 '19 at 08:46
  • I don't pass any options. I'm not in a tmux session, the above is run upon login via ssh. – lonix Nov 17 '19 at 08:52
  • You are changing the code in the question an awful lot. The original question did not have any `if`-statements at all. The command substitution in your update does not make sense and would execute the output of `tmux new-session` whenever that session terminated. There is otherwise no difference between the two codes. Also, consider using `exec` as when one of your `tmux` sessions exits, it would give you an interactive `bash` shell (on the remote host) without `exec`. – Kusalananda Nov 17 '19 at 09:09
  • @Kusalananda Sorry. I only wrapped it in the `if` check to give context, I left it out initially to keep it simple. I didn't realise it was having an effect, as the error was the same regardless. Thanks again. – lonix Nov 17 '19 at 09:13

1 Answers1

6

To start tmux automatically in ~/.bash_profile (for login shells), or ~/.bashrc (for interactive shells), use something like

if [[ -z $TMUX ]] && [[ -n $SSH_TTY ]]; then
    session=mysession

    if tmux has-session -t "$session" 2>/dev/null; then
        exec tmux attach-session -t "$session"
    else
        exec tmux new-session -s "$session"
    fi
fi

This would replace the shell with a tmux session if the shell is started by ssh, unless the current shell is already running inside tmux.

With newer versions of tmux, you should instead be able to use

if [[ -z $TMUX ]] && [[ -n $SSH_TTY ]]; then
    exec tmux new-session -A -s mysession
fi

You would want to do this after setting variables like TERM and LC_* (if you set these) that affect the terminal capabilities and locale.

Remember that ssh needs a pseudo-tty to run tmux, so you must connect with ssh -t (or use RequestTTY force in ~/.ssh/config for the connection).

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • I tried your new approach and it works reliably! Thanks. I added the `&& [[ $- =~ i ]]` check so it works for ansible. One question though, why is it when I exit tmux it also closes the ssh session? – lonix Nov 17 '19 at 09:10
  • @lonix If you remove `exec` from my code, the original shell session that starts `tmux` would finish initializing, giving you a `bash` shell. With `exec`, the login shell is replaced by `tmux`, which means that the SSH session would exit when `tmux` terminates. – Kusalananda Nov 17 '19 at 09:12
  • Aaah that makes sense now. Your way is very elegant, thank you! – lonix Nov 17 '19 at 09:14
  • Sorry, one last question, really - when I add your code to `.bash_profile` it works, but it removes all terminal coloring (e.g. when using 'ls`, etc.) But when I add it to `.bashrc` the colors are shown as expected. I'm using ubuntu 19.10. Is this a weird config problem that is my fault, or is there a reason for it? – lonix Nov 17 '19 at 09:26
  • @lonix Put it towards the _end_ of the file, after any terminal initializations or other things you may do there. You could obviously have it in `.bashrc` instead. In fact, I don't think it matters as I just remembered that `tmux` spawns logins shells by default (so it would try to run `~/.bash_profile` regardless, which makes my note about that wrong, so I will change it). – Kusalananda Nov 17 '19 at 09:30
  • Thanks again, I moved it to `.bashrc` and now it's perfect! – lonix Nov 17 '19 at 09:33
  • `.bashrc` will also be sourced by **non-interactive** shells, when bash guesses (via some unreliable heuristics) that it was started by ssh. `SSH_TTY` will also be set when using `ssh -t some_command`, not only when an interactive shell was started. Executing another program from `.bashrc` has the potential of breaking things in other perverse ways (e.g. because bash is sourcing its start-up files with the job control turned off). –  Jan 13 '21 at 06:50
  • @user414777 Thanks! I forgot that `bash` uses heuristics under some circumstances. – Kusalananda Jan 13 '21 at 06:53