12

I'm using zsh 5.0.8 version in iterm2 on OSX.

I start my computer and printenv shows me the $PATH variable:

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/git/bin

from my understanding, zsh will source the following file in order:

/etc/zshenv
~/.zshenv
/etc/zshrc
~/.zshrc

I checked, I don't have the first 3 files, and my .zshrc is basically empty, nothing related to the $PATH variable.

Then where is the $PATH variable set???

2 Answers2

22

I literally just had a battle with this today.

On OS X Yosemite PATH is built up in a rather roundabout way.

I believe that, as cremefraiche says, ZSH has a built-in $PATH that it uses if nothing else is set, but that's not where yours is coming from. First of all there is a file, /etc/paths, that contains a list of directories. There is also a directory, /etc/path.d that contains more files that contain directories. The program /usr/libexec/path_helper takes these lists of directories, merges them with the existing $PATH variable (if there is one), removes any duplicates, and outputs the result, with the /etc/paths directories listed first.

You can try running it yourself, it doesn't do any harm. Here's the output from mine:

$ /usr/libexec/path_helper 
PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/MacGPG2/bin:/Users/alan/.local/bin:/Users/alan/src/go/bin"; export PATH;

On it's own, this doesn't do anything, but it's called from, on my machine, /etc/zprofile:

if [ -x /usr/libexec/path_helper ]; then
    eval `/usr/libexec/path_helper -s`
fi

This might vary on your machine, as it seems Apple have moved this code around a bit in different versions of OS X.

Here's the list of all the files that ZSH reads in OS X, in the order they are evaluated:

  1. /etc/zshenv
  2. ~/.zshenv
  3. /etc/zprofile
  4. ~/.zprofile
  5. /etc/zshrc
  6. ~/.zshrc
  7. /etc/zlogin
  8. ~/.zlogin
  9. ~/.zlogout
  10. /etc/zlogout

Some of these files aren't evaluated in certain circumstances, like when run as non-interactive shell scripts, but I'm not going to discuss that here. It's in the ZSH man page if you're interested.

$ man zsh

It's worth noting that /etc/zprofile is run after ~/.zshenv, so if you follow the ZSH guidelines and set your $PATH in .zshenv, it's probably going to be clobbered by path_helper. If you're running into this problem it might be worth renaming /etc/zprofile as /etc/zshenv so the system $PATH will be set as early as possible.

  • in ubuntu 20.04 the system-wide zsh config files (eg. zprofile zshenv) are inside /etc/zsh. but this response is still helpful – yaitloutou Jul 11 '20 at 22:28
  • 2
    It's specifically about how it works on macOS so it shouldn't be too surprising that Ubuntu does things differently. – Alan Third Aug 03 '20 at 13:00
1

This refers to bash, but I suspect is applicable to zsh as well.

The default value of PATH is determined when bash is compiled. It is not set in a startup file, although it might be modified there.

A Practical Guide to Fedora and Red Hat Enterprise Linux: Seventh Edition. p359.

Edit

I did some more digging and found that the default PATH is in fact set during compilation, and can be found in the init.c file.

/* Set default path */
path    = (char **) zalloc(sizeof(*path) * 5);
path[0] = ztrdup("/bin");
path[1] = ztrdup("/usr/bin");
path[2] = ztrdup("/usr/ucb");
path[3] = ztrdup("/usr/local/bin");
path[4] = NULL;

EDIT2:

I went into zsh IRC on freenode, and a dev was able to give me a list of four different commands that all demonstrate that the PATH is set in compilation. I posted these commands in the extended chat, but did not realize they would be lost after X amount of time. Ask devs in IRC to demonstrate if you would like to see for yourself.

cremefraiche
  • 555
  • 3
  • 9