This post is now obsolete. For the preferred method in both Mountain Lion and Mavericks, see Setting environment variables in OS X Mountain Lion and Mavericks. With Mountain Lion (OS X 10.8), the environment settings from ~/.MacOSX/environment.plist are not taken into account when the background system environment is set up by launchd, the OS X initialisation process. Consequently, if you want settings like $JAVA_HOME to be available to Java applications you start from Finder, you must find an alternative for setting them.
The beauty of the environment.plist method was that, by setting the variables in the plist from within your .profile, you could keep the shell and system environments in sync. There are obvious advantages in this synchronisation. If you are like me, you have gone to a lot of trouble to put such synchronisation in place. See my previous post, Setting Environment Variables in OS X Lion.
The now-recommended method of system variable setting is to use the setenv subcommand of launchctl, like so:
launchctl setenv M2 /usr/share/maven/bin
Such commands can be saved in the file /etc/launchd.conf, in which case only the subcommand is saved:
setenv M2 /usr/share/maven/bin
You can check the state of the launchd environment with the subcommand export:
launchctl export
This will output a series of shell commands of the form
M2=" /usr/share/maven/bin"; export M2;
This serves as a test for any attempts to set the launchd environment variables.
There are three problems with using launchctl in this way. Firstly, /etc/launchd.conf is a system file (when it exists, which it does not by default), and it is in a directory (/etc) which is writable only by root. Yes, you can sudo to edit the file, but then you face the second problem, touched on above. You have two discrete sources for environment variable settings, which can easily get out of sync. Lastly, the strings defined in setenv statements like the above, must be string literals. There is no means of resolving variable content based on other variables. For example, you cannot define
setenv TMPDIR $HOME/tmp
The problem, then, is to find a way to dynamically set the launchd environment, based on your existing .profile and .MacOSX/environment.plist settings. Another bonus from this approach is that, within you .profile, you can use all of the shell facilities to define the content of variables.
The executable: plist2launchctl
#!/bin/sh PLIST="$HOME/.MacOSX/environment.plist" SLEEP_TIME=10 # Uncomment following to echo launchctl commands to stdout # Key StandardOutPath will have to be set in the plist file # (au.id.pbw.plist2launchctl) for output to be captured. #ECHO_TO_STDOUT=true one_cmd () { eval "$@" } [[ -e "$SHFILE" ]] && { rm "$SHFILE" [[ $? -eq 1 ]] && { echo "$SHFILE" cannot be removed. >&2 exit 1 } } cmd_list=`cat "$PLIST" | sed -En '/^[[:space:]]*<key>(.*)</key>[[:space:]]*/ { s//launchctl setenv 1 / N } /^.*<string>.*[[:space:]].*</string>.*$/ { d } /^(launchctl .*)n[[:space:]]*<string>(.+)</string>[[:space:]]*$/ { s//12/ p d }'` [[ -n "$ECHO_TO_STDOUT" ]] && echo "$cmd_list" echo "$cmd_list" | while read line; do one_cmd $line; done [[ -n "$ECHO_TO_STDOUT" ]] && echo Sleeping in plist2launchctl # Sleep for a while so launchd doesn't get upset [[ -n "$SLEEP_TIME" ]] && sleep "$SLEEP_TIME"
Notes:
The output of the whole of the cat|sed pipeline is captured in the cmd_list variable by enclosing the lot in backquotes. The sed command is itself enclosed in single quotes. It simply reads the contents of environment.plist line at a time, and merges key/string pairs into the corresponding launchctl setenv commands, storing them in cmd_list. cmd_list is then itself read line at a time, and each line is handed to eval for execution.
Permissions & Location:
To stay on the safe side, give the file -rwxr-xr-x permissions. It should be placed in /usr/libexec, which is root owned. You will have to use sudo to copy it.
The plist file: au.id.pbw.plist2launchctl
<? 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>au.id.pbw.plist2launchctl</string> <key>KeepAlive</key> <false/> <key>Program</key> <string>/usr/libexec/plist2launchctl</string> <key>RunAtLoad</key> <true/> <key>UserName<key> <string>pbw</string> </dict> </plist>
The UserName field will, of course, be set to your own login name.
If you need to debug the plist file, add the following lines.
<key>StandardOutPath</key> <string>/Users/pbw/plist.log</string> <key>Debug</key> <true/>