Setting environment variables in OS X

Posted by Percival Ulysses on Super User See other posts from Super User or by Percival Ulysses
Published on 2012-09-18T21:00:26Z Indexed on 2012/09/18 21:41 UTC
Read the original article Hit count: 248

Despite the warning that questions that can be answered are preferred, this question is more a request for comments. I apologize for this, but I feel that it is valuable nonetheless.

The problem to set up environment variables such that they are available for GUI applications has been around since the dawn of Mac OS X. The solution with ~/.MacOSX/environment.plist never satisfied me because it was not reliable, and bash style globbing wasn't available. Another solution is the use of Login Hooks with a suitable shell script, but these are deprecated.

The Apple approved way for such functionality as provided by login hooks is the use of Launch Agents. I provided a launch agent that is located in /Library/LaunchAgents/:

    <?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>user.conf.launchd</string>
        <key>Program</key>
        <string>/Users/Shared/conflaunchd.sh</string>
        <key>ProgramArguments</key>
        <array>
            <string>~/.conf.launchd</string>
        </array>
        <key>EnableGlobbing</key>
        <true/>
        <key>RunAtLoad</key>
        <true/>
        <key>LimitLoadToSessionType</key>
        <array>
            <string>Aqua</string>
            <string>StandardIO</string>
        </array>
    </dict>
    </plist>

The real work is done in the shell script /Users/Shared/conflaunchd.sh, which reads ~/.conf.launchd and feeds it to launchctl:

    #! /bin/bash

    #filename="$1"
    filename="$HOME/.conf.launchd"

    if [ ! -r "$filename" ]; then
        exit
    fi

    eval $(/usr/libexec/path_helper -s)

    while read line; do
        # skip lines that only contain whitespace or a comment
        if [ ! -n "$line" -o `expr "$line" : '#'` -gt 0 ]; then continue; fi

        eval launchctl $line
    done <"$filename"

    exit 0

Notice the call of path_helper to get PATH set up right. Finally, ~/.conf.launchd looks like that

    setenv PATH ~/Applications:"${PATH}"

    setenv TEXINPUTS .:~/Documents/texmf//:
    setenv BIBINPUTS .:~/Documents/texmf/bibtex//:
    setenv BSTINPUTS .:~/Documents/texmf/bibtex//:

    # Locale
    setenv LANG en_US.UTF-8

These are launchctl commands, see its manpage for further information. Works fine for me (I should mention that I'm still a Snow Leopard guy), GUI applications such as texstudio can see my local texmf tree. Things that can be improved:

  1. The shell script has a #filename="$1" in it. This is not accidental, as the file name should be feeded to the script by the launch agent as an argument, but that doesn't work.

  2. It is possible to put the script in the launch agent itsself.

  3. I am not sure how secure this solution is, as it uses eval with user provided strings.

It should be mentioned that Apple intended a somewhat similar approach by putting stuff in ~/launchd.conf, but it is currently unsupported as to this date and OS (see the manpage of launchd.conf). I guess that things like globbing would not work as they do in this proposal.

Finally, I would mention the sources I used as information on Launch Agents, but StackExchange doesn't let me [1], [2], [3]. Again, I am sorry that this is not a real question, I still hope it is useful.

© Super User or respective owner

Related posts about osx

Related posts about environment-variables