How does Mac OS X set the value of $PATH?

Usually, your PATH is set by the shell. For Bash, everything is explained in the manual. You can also open man bash and skip to the INVOCATION part.

Invoked as an interactive login shell, or with --login

When Bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.

Invoked as an interactive non-login shell

When an interactive shell that is not a login shell is started, Bash reads and executes commands from ~/.bashrc, if that file exists. In OS X, additionally, there is path_helper which reads the contents of /etc/paths.d and appends those to your path.

The key here is that on OS X, the Terminal opens a login shell by default, while on Linux, shells are usually started as non-login shells. Josh Staiger has a good explanation of login vs non-login shells.

So, there are essentially only these two three where you can set paths:

  • /etc/profile (which calls path_helper)
  • /etc/paths and /etc/paths.d (called from path_helper)
  • your shell configuration file (.bash_profile)

The paths in /etc/paths and /etc/paths.d/* are typically added to PATH by path_helper. path_helper is run from /etc/profile, so it is run when bash is invoked as an interactive login shell, but not when bash is invoked as a non-login shell or a non-interactive shell.

/etc/paths contains /usr/local/bin at the end by default, and /etc/paths.d/ is empty by default.

Terminal and iTerm 2 open new shells as login shells by default, and the shell opened when you ssh to your computer is also a login shell. Many terminal emulators on other platforms, tmux, and the shell mode in Emacs open new shells as non-login shells though.

I have added this line to /etc/launchd.conf:

setenv PATH ~/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/libexec:/usr/texbin

It changes the value of PATH of the root launchd process. The value is inherited by all other processes, including per-user launchd processes. You can apply changes to /etc/launchd.conf by restarting, or by running launchctl < /etc/launchd.conf; sudo launchctl < /etc/launchd.conf and relaunching processes.

On OS X, ~/.profile is not read when you log in graphically. If both ~/.bash_profile and ~/.profile exist, bash does not read ~/.profile either.

~/.MacOSX/environment.plist stopped working in 10.8.