Search code examples
shelltmuxfish

why including exec tmux in config.fish doesn't work


i'm trying to set fish run tmux, automatically on login. so i added the following to the top of my config.fish file.

if status is-interactive
    exec tmux
end

but now if i open a new terminal window it closes immediately. but found this answer here which actually works

if status is-interactive
and not set -q TMUX
    exec tmux
end

Apparently what it does is it also checks if tmux is not already activated, but how does that help when i'm sure no tmux session is active and what's the problem with first code i was trying to use.

let me add running the first one in shell (not putting it in config file) works perfectly.


Solution

  • When you do exec tmux, that replaces the shell process with tmux.

    Tmux will then start another shell, which reads its config file and... replaces itself with tmux. Which will then start another shell, which reads its config file and replaces itself with tmux.

    It's an infinite loop. That's why you need to check if tmux is already one of the parent processes, which $TMUX being set is an indication for (technically any old process could set that variable, it's not protected or anything, the recommendation there is to just not do that).


    The reason it exits instead of actually looping forever is that tmux checks $TMUX - if you try to run tmux inside of a tmux session it'll tell you:

    sessions should be nested with care, unset $TMUX to force

    and then exit. So:

    • fish becomes tmux
    • which sets $TMUX
    • starts another fish
    • which becomes another tmux
    • which refuses because $TMUX is already set and exits

    Because the leading process has exited, the outer tmux also exits - and since that's the top process in your terminal (because it used to be fish) your terminal tab closes.

    But regardless of how this fails, doing this without checking for $TMUX is never going to make any sense.


    You can see what would happen if you just kept starting tmux by doing the opposite of only doing it when $TMUX isn't set - only do it when TMUX isn't set, and clearing it:

    if set -q TMUX
        set -e TMUX
        exec tmux
    end
    

    When you then start TMUX=foo fish, it will see that $TMUX is set, erase it, become tmux. Tmux will then set $TMUX and start another fish, which will erase $TMUX and become another tmux.

    This will fill your terminal with multiple copies of the tmux bottom bar and not actually allow you to do anything!

    So if you do try this, you should keep a separate terminal open or have a separate login shell that you can use to stop it (by removing the lines from config.fish again). Do ensure that you have a way to remove this again, it's a fun experiment but could, under the right circumstances, wreck your ability to start a terminal.