When I use ZSH, how do I set PATH in /etc/profile.d?

Solution 1:

From my point of view, the best way is to add the following lines at the ~/.zshrc file (if you don't already have it, then create it):

if [ -d "/path/to/jdk" ] ; then
    export PATH="/path/to/jdk/bin:$PATH"
fi

Then restart your zsh, or just run source ~/.zshrc and then your PATH should be exactly as you wish.

Or, if you want to make the change to be system-wide, then add the previous code to the end of /etc/zsh/zshenv file.

But in any case do not use /etc/profile.d to automatically run scripts in zsh. This directory is useful only for the bash shell, not zsh as in your case. To understand this, open /etc/profile file, which is a bash initialization file and in no case a zsh initialization file, and you will see somewhere at the end of the file:

if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

So, your scripts from /etc/profile.d directory will automatically run in zsh only if you add the previous code in a zsh initialization file, like /etc/zsh/zprofile for example, or source /etc/profile in /etc/zsh/zprofile file.

Solution 2:

I find that placing everything in one .zshenv file quickly becomes hard to manage. I recommend installing oh-my-sh and then placing various customizations (env vars, functions) to the .oh-my-sh/custom/ directory as separate .zsh files.

I also discovered that this approach works flawlessly when ssh'ing into machine when modifying env variables such as PATH. Also it works really nice together with vcsh for keeping customizations backed up and in sync.

Solution 3:

Since JAVA_HOME is set, you have confirmed that those scripts are sourced automatically, haven't you?

The only logical explanation is that PATH is set later on somehow. It should be originally set by PAM which reads /etc/environment, and as far as I know that happens before /etc/profile.d/*.sh files are sourced. Possibly zsh works different compared to bash in that respect.