tmux has an interesting quirk in the way it handles environment variables that if you’re not careful can cause some seemingly strange behavior.

Fortunately, this behavior is documented but in my opinion, is not intuitive. From the tmux man page:

When the server is started, tmux copies the environment into the global environment; in addition, each session has a session environment. When a window is created, the session and global environments are merged. If a variable exists in both, the value from the session environment is used. The result is the initial environment passed to the new process.

What this says is that the global environment is copied over when the server is started. Each session also has an environment that is merged with the original global environment but it only has a set list of environment variables that are updated. You can see this with the following command in a tmux session:

> tmux show-environment
-DISPLAY
-KRB5CCNAME
-SSH_AGENT_PID
-SSH_ASKPASS
SSH_AUTH_SOCK
-SSH_CONNECTION
-WINDOWID
-XAUTHORITY

This can cause some interesting consequences when you have multiple named tmux sessions running. Here’s an example of this in action:

> export FOO=foo
> tmux new-session -t first
> echo $FOO
foo

> export FOO=bar
> tmux new-session -t second
> echo $FOO
foo

As long as the tmux server is running, it will retain the copy of the environment at the moment it was started and unless the environment variable is in a set list it will not be updated when a new session starts even if its a completely separate session.

There are a few different ways to work around this. If you know you’ll want a specific environment variable updated each time you start a new session, you can add the variable to the global update list.

tmux.conf

set-option -g update-environment "FOO"

This will tell tmux the session environment for $FOO whenever a new session is created or an existing session is attached to.

Alternatively, you can manually update the environment using tmux set-environment this can be applied to either the global environment so that each new session picks up the new value or for a specific session.

Lastly, you can avoid the problem altogether by providing a named socket to tmux using -L which will cause a new server to start and copy the current environment into the global environment.

> export FOO=foo
> tmux new-session -t first
> echo $FOO
foo

> export FOO=bar
> tmux -L other new-session -t second
> echo $FOO
bar

This does make the ergonomics for tmux a little more cumbersome since you’ll need to provide the name of the socket each time you want to run tmux commands. For example, to re-attach to the second session you’ll need to do tmux -L other attach -t second.

Tags: