macOS Terminal – How PATH is Calculated

environment-variablesmacosterminalui

I've read a dozen different answers and talked to a bunch of people and am having difficulty understanding how PATH is calculated in different scenarios. Specifically I'm thinking of

  1. How exactly is PATH calculated for bash?
  2. How exactly is it calculated for other shells? (I assume its shell dependent, but what is the commonality between all shells?)
  3. How exactly is it calculated for GUI apps?
  4. Am I missing another way of launching stuff? Do daemons do something different? (I don't think so? But maybe…)

Additionally I'm on High Sierra now but I'm seeing some people mentioned that this changed at some point?

I've seen this answer and this one but both seem to be focused explicitly on what happens inside of bash.

Best Answer

I'm going to lump together 1 & 2 because all shells read files at startup.

PATH is inherited from its parent process. This is a key concept that you need to understand.

The PATH is first hard coded into the kernel:

sysctl user.cs_path
user.cs_path: /usr/bin:/bin:/usr/sbin:/sbin

launchd which acts as init can be configured to change this PATH. Generally it is not changed.

The loginwindow.app will setup an environment when you log into your computer. PATH will be checked that it has been set or it will be set to the hard coded path in the kernel or a modified path set by launchd. It is like the loginwindow.app is calling login -pf <username>.

At this point, a user LaunchAgent or LaunchDaemon may modify the PATH.

This will be the PATH available to GUI applications from the Finder. (Early versions of OS X could use ~/.MacOSX/environment.plist to change the PATH for GUI applications). Now if this seems complicated, it's not and more that likely,like me, the PATH available is /usr/bin:/bin:/usr/sbin:/sbin

When you start the Terminal.app, it first calls login (login -pf ) which triggers your shell to be treated as a login shell. The appropriate files in /etc and your HOME folder are read. Now, PATH should be different than set by the loginwindow.app. Remember we talked about inheritance? If you start a GUI app from within your terminal session then the PATH available to GUI application will be same as set by the shell.

As far as daemons, they are usually started by their absolute path.