New tmux session only sources .zshrc, and doesn't pick up the $PATH defined in .profile

6,588

Solution 1

The behavior you describe is the expected one. Environment variables are defined in .profile, which is read when you log in. Starting a new tmux session does not log you in. Tmux does start a login shell by default, but you've turned this off in the configuration, so the tmux windows just inherit the outside environment.

If you put source .profile in your .zshrc, this overrides whatever environment the shell is running in. This means that you can't run a shell inside a different environment from your default one, e.g. to try something with a different PATH.

Just remove source .profile from .zshrc. You'll have your default environment, set at login time, in all shells.

If your login shell is zsh, note that it reads .zprofile at login time, not .profile. This is different from bash, which reads .profile if there is no .bash_profile. Zsh works differently because its syntax is different from sh, so it can't read .profile directly. If you want to have a .profile that works under sh for GUI logins and to also use the same file for text mode logins, and you have zsh set as your login shell, then use the following line as your ~/.zprofile:

emulate sh -c 'source ~/.profile'

If tmux is configured to run a login shell, then all tmux windows will override the surrounding environment instead of inheriting it. This means that if you define new variables outside of tmux, you'll still have them in the tmux session, but if you change the values of variables that are already defined then your changes will be lost inside tmux. All in all, tmux's default behavior doesn't make much sense. Avoiding this is the point of the set-option -g default-command $SHELL line in ~/.tmux.conf.

If you use tmux as a way to do a “fresh login”, you may prefer to have each window run in a fresh environment. If so, then you should probably clean up your environment with something like

set-option -g default-command env -i USER="$USER" LOGNAME="$LOGNAME" $SHELL

And remember that if your login shell is zsh then it reads .zprofile, not .profile.

Solution 2

You should remove your the set-option -g default-shell $SHELL from .tmux.conf; it's not necessary, because tmux will use the SHELL envvar by default.

This is what the manpage says:

     default-shell path
             Specify the default shell.  This is used as the login
             shell for new windows when the default-command option is
             set to empty, and must be the full path of the exe-
             cutable.  When started tmux tries to set a default value
             from the first suitable of the SHELL environment vari-
             able, the shell returned by getpwuid(3), or /bin/sh.
             This option should be configured when tmux is used as a
             login shell.

tmux will start a login shell (ie a shell that is sourcing ~/.profile or ~/.zprofile -- and ~/.zlogout or ~/.bash_logout before exiting) by default:

     default-command shell-command
             Set the command used for new windows (if not specified
             when the window is created) to shell-command, which may
             be any sh(1) command.  The default is an empty string,
             which instructs tmux to create a login shell using the
             value of the default-shell option.

See here for a discussion about this behavior -- which is quite surprising and different from that of screen.

So, if you want tmux to start a non-login shell using your default shell, put the following in your ~/.tmux.conf:

set -g default-command $SHELL

and if you want it to run a login shell with another shell than your default one:

set -g default-command "/alternative/sh -l"
Share:
6,588
xji
Author by

xji

Updated on September 18, 2022

Comments

  • xji
    xji over 1 year

    After reading multiple questions on this topic I still feel lost. I read suggestions that one should set the environment variables including $PATH in .profile instead of specifically in .bashrc or .zshrc, and this is what I did.

    My default shell is zsh and I have set set-option -g default-shell $SHELL in tmux.conf.

    However, now whenever I launch tmux sessions, it apparently doesn't pick up any modification to $PATH and only sources .zshrc. My current workaround is to add source ~/.profile at the end of .zshrc, which I don't think is the right thing to do.

    This post indicates that tmux/screen usually runs as subshells instead of login shells, and thus don't necessarily source .profile. However, another post claimed that if you can run logout in the shell, it is a login shell, which I was indeed able to. Many posts also claimed that tmux should look for .bash_profile plus .profile, but would overlook .bashrc, which is apparently not what happened in my case of the zsh equivalent.

    What is the best practice to use tmux with zsh and have it properly pick up environment variables, after all?

  • mosvy
    mosvy over 5 years
    that's not true, starting a new tmux does start a login shell by default. See here and here. This is still the case with the latest tmux from git.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 5 years
    Yes, that's a problem with tmux: it starts a login shell when it has no business to do so. The point of set-option -g default-shell $SHELL is precisely to avoid this. But with or without this option, it still inherits the environment variables that were set at login time (unless overridden by the tmux or shell initialization).
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 5 years
    @mosvy I don't see any statement in my answer that is not true. It was incomplete because I'd forgotten about this tmux behavior, but either way, it still runs an environment that's derived from the login-time environment.
  • mosvy
    mosvy over 5 years
    "Starting a new tmux session does not start a login shell: you're already logged in." -- that's not true, unless you want to redefine "login shell" to something else than the usual definition: "A login shell is one whose first character of argument zero is a -, or one started with the --login option."
  • mosvy
    mosvy over 5 years
    a) modern desktop environments can no longer be trusted to pass everything from ~/.profile to subprocesses b) the OP didn't indicate that they logged out and then in from their session in order to test changes to ~/.profile. And, as you mentioned, zsh may not source ~/.profile, but only ~/.zprofile -- that may cause another bout of confusion depending on where tmux was started from.
  • xji
    xji over 5 years
    Thanks. Apparently I didn't know the difference between .zprofile and .profile and that caused my confusion.