Hack 52 Setting Shell Environment Variables

figs/expert.giffigs/hack52.gif

An environment variable is a magical piece of invisible data that is acted upon by shell programs and utilities that look for its existence. They're innocent enough and you rarely interact with them, but they can prove to be quite powerful and time saving when used as part of your daily lifestyle.

Smart developers who care about code integrity use something called a versioning system to ensure a system of checks and balances, easy reversion to previous code, and preventive overwriting (by an automatic or manual merging process). It's such a common part of a developer's toolkit that the popular open source web IDE Sourceforge.net provides it as a default service.

One annoyance of Concurrent Versioning System (CVS) (longtime users can find many more) is the command line ? without an enviroment variable, you have to type your cvsroot each and every time you make any changes to your repository:

cvs -d:pserver:anonymous@cvs.amphetadesk.sourceforge.net:/cvsroot/amphetadesk login
cvs -z3 -d:pserver:anonymous@cvs.amphetadesk.sourceforge.net:/cvsroot/amphetadesk co AmphetaDesk

These two lines log you into a CVS server as the user anonymous and then check out the entire source tree of a program called AmphetaDesk. A cursory examination shows that the largest part of the command line is the -d flag; it's also repetitive, as it needs to be a part of every cvs command. It can make a person nuts when she has to worry about committing modifications to a dozen different files. Wouldn't it be great if you never had to type the -d flag and its heavy payload?

Thankfully, using environment variables, you don't. Think of an environment variable as a configuration file; the values are acted upon only by the application that knows how to handle them. Instead of being located in seperate config files, they're loaded into the shell environment. You can think of them (roughly) as preferences for your shell (as opposed to preferences for the OS X Terminal application). The environment variable you want to set is called, semantically enough, CVS_ROOT (named after what the -d flag represents).

If you haven't been fiddling with the Terminal preferences, then you're using the tcsh shell. There are lots of different types of shells, tcsh being the default on OS X (with an additional choice of bash under 10.2). Setting an environment variable will change depending on which shell you're using, but under tcsh, enter the following:

setenv CVS_ROOT "-d:pserver:anonymous@cvs.amphetadesk.sourceforge.net:/cvsroot/amphetadesk"

If, on the other hand, you've tweaked Terminal to use bash, enter the following instead:

export CVS_ROOT="-d:pserver:anonymous@cvs.amphetadesk.sourceforge.net:/cvsroot/amphetadesk"

With the preceding command, you'll notice that nothing seems to happen. That's because environment variables are invisible ? there's only visual feedback when you've screwed up the previous command (or else use a program that uses the variable). To see your variable set properly, type printenv (for either shell). You'll see your CVS_ROOT, as well as a number of other variables already defined by OS X.

You can now enter the much smaller, and more readable, commands:

cvs login
cvs -z3 co AmphetaDesk

The problem with setenv and export are that they're both temporary; once you close the Terminal, your CVS_ROOT will be forgotten and you'll be back in the forest with a command line a mile long. What do you do? Make it permanent, of course.

Doing so again differs depending on what shell you've chosen. Each shell has the ability to read a startup file ? something you create that says "hey, everytime I start this shell, do the commands within this file." These files are located in your home directory and normally are not visible to the Finder. With the tcsh shell, the file is named .tcshrc; under bash, it's .bash_profile. Creating those files, adding the matching command from before, and then starting a new Terminal window will set the CVS_ROOT at startup (you can check this with the printenv command).

Another alternative is using the plist preference file format. More information is available in the See Also section later in this hack, but creating a file at ~/.MacOSX/environment.plist with the following contents would do it for you:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>CVS_ROOT</key>
<string>-d:pserver:anonymous@cvs.amphetadesk.sourceforge.net:/cvsroot/amphetadesk</string>
</dict>
</plist>

52.1 See Also

  • Setting environment variables (http://developer.apple.com/qa/qa2001/qa1067.html)