MacOS – Making items added to paths via paths.d show up everywhere under Mavericks

environment-variableslaunchdmacospath

I'd like to set the path under OS X Mavericks so that the setting shows up everywhere (e.g., in .apps and in Darwin shells). There's plenty of discussion out there about how to set environment variables generally under OS X. With environments.plist no longer supported by Mavericks, it seems that editing /etc/launchd.conf is the best option for doing so. Unfortunately, launchd.conf apparently does no parameter expansion, so I can't do this:

setenv PATH /Users/kuzzooroo/anaconda/bin:$PATH

and I don't want to hardcode my entire path–it seems unmaintainable.

There's another question in AskDifferent specifically about setting the system-wide PATH environment variable in Mavericks. The accepted solution is to use /etc/paths.d/, but someone has posted the following comment (which has garnered several upvotes) as a caveat:

Paths in paths.d are added to the path by path_helper, which is run from /etc/profile and /etc/csh.login, but not when for example bash is invoked as a non-interactive or non-login shell or when you run programs in text editors.

Is there a way I can make these environments pull in paths.d (for example, by putting a command to process paths.d into some bash configuration file that is run even for non-interactive shells)?

Best Answer

Option 1: just use /etc/launchd.conf

Add a line like

setenv PATH /Users/username/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

to /etc/launchd.conf and restart to apply the changes.

The default path is /usr/bin:/bin:/usr/sbin:/sbin.

/etc/launchd.conf applies to all processes, which includes graphical applications, non-login shells, and programs started by launchd jobs.

Edit /etc/launchd.conf manually if you see that some program or installer has added new paths to /etc/paths or /etc/paths.d/*.

Option 2: use a launchd job to set the path during startup

Save this plist as /Library/LaunchDaemons/setpath.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>setpath</string>
  <key>ProgramArguments</key>
  <array>
    <string>bash</string>
    <string>-c</string>
    <string>launchctl setenv PATH "$((launchctl getenv PATH|tr : \\n
    cat /etc/paths /etc/paths.d/*)|awk '!a[$0]++'|paste -sd: -)"</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

The program should be run the next time you restart. It changes the PATH of the root launchd process, which is inherited by the user launchd process.

In my opinion it's easier to just edit /etc/launchd.conf though.

Option 3: make bash run path_helper even for non-login shells

path_helper is run from /etc/profile, /etc/zshenv, and /etc/csh.login. zsh reads /etc/zshenv even for non-login shells but bash does not read /etc/profile for non-login shells.

This makes bash run path_helper for interactive non-login shells and for non-interactive non-login shells:

echo 'eval $(/usr/libexec/path_helper -s)'>>~/.bashrc
setenv BASH_ENV /etc/profile|sudo tee -a /etc/launchd.conf

It does not make bash run path_helper for non-interactive non-login shells invoked as sh. It also does not affect graphical applications or processes that are not started from shells.