How exactly is PATH calculated?
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.
From the man page for PATH (man path
):
The search path for commands. It is a colon-separated list of directories in which the shell looks for commands (see COMMAND EXECUTION below)....The default path is system-dependent, and is set by the administrator who installs bash. A common value is ``/usr/gnu/bin:/usr/local/bin:/usr/ucb:/bin:/usr/bin''.
So, from that except from the bash man page, we see that the bash path is (initially):
- system dependent and not shell dependent
- set by the one who installed bash (in this case Apple)
- has a default value
The path can (obviously) be modified. There are several places where the PATH environment variable can be set:
~/.bashrc
~/.bash_profile
In macOS, the file /etc/paths
is used to configure the search paths:
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
Additionally, the path is initially configured by the /usr/libexec/path_helper
utility which will create a path based on the contents of /etc/paths.d
It's called from /etc/profile
which sets the system wide bash profile (individual ones are set in ~/.profile
)
As for GUI apps, the shell path really has no effect. The only time a GUI application (Cocoa, Quartz, Metal) has anything to do with PATH is when it opens a shell (either interactive or non-interactive). At that point it will use the PATH environment as set or make whatever changes it needs at run time.
Different Shells
Each of the shells have a different system wide profile (as does bash) which set's the initial PATH (by calling the path_helper
utility)
- Zsh =
/etc/zprilfe
- Ksh =
/etc/profile
- Csh =
/etc/csh.login