Previous | Table of Contents | Next |
Tailoring Your Path
At many companies and schools, a users home directory is accessible from many machines running different versions of UNIX. A problem that I face every day is using my shell initialization script, .profile, on Linux, Solaris, FreeBSD, and HP-UX machines.
Although many issues arise involving cross-platform initialization scripts, one of the largest issues is getting your PATH variable set correctly. Because each different UNIX platform stores commands in different directories, your initialization script must be able to tailor the value of the variable PATH. This problem has four possible solutions:
The first two solutions are difficult to maintain. Each change or new UNIX version that you have to work with means that you have to create either a new initialization file or a new section on your initialization file. The complexity of your shell initialization process increases drastically with either of these approaches.
The third option is easy to implement and maintain, but it results in a PATH that is extremely long and hard to restructure. If you have more than one or two machines, PATH can grow to contain dozens of entries.
The fourth option is the easiest to maintain and extend, so how do you implement it?
The simplest way is to have a for loop that checks each directory and includes it if it exists:
PATH= for DIR in /bin /sbin /usr/bin /usr/sbin /usr/ccs/bin /usr/ucb ; do if [ -d "$DIR" ] ; PATH="$PATH:$DIR" ; fi done export PATH
At this point you might wonder why I am discussing this problem in this chapter and not in a previous chapter. The reason is that the complete problem is more than simply tailoring PATH on a per-UNIX-version basis. The complete problem requires you to tailor PATH for both interactive shells and for different user IDs.
You can solve these problems by including several case statements with different for loops in them, or you can write one function and reuse it. Because this chapter covers functions, I will show you how to do the latter.
The function that you need is quite simple. Rewrite the for loop to use the functions arguments rather than a list of directories:
SetPath() { for _DIR in "$@" do if [ -d "$_DIR" ] ; then PATH="$PATH":"$_DIR" ; fi done export PATH unset _DIR }
This function has three important points:
There is only one additional thing to add to this function, and that is to check to see whether PATH is set. Without this check, you can potentially end up with a PATH set to
PATH=:/usr/bin:/usr/sbin:/usr/local/bin
The problem here is that the first entry in the variable PATH appears to be a null string. Some versions of the shell cannot deal with this entry, so you need to prevent this from happening.
You can do this check using variable substitution. The complete function is
SetPath() { PATH=${PATH:="/sbin:/bin"}; for _DIR in "$@" do if [ -d "$DIR" ] ; then PATH="$PATH":"$DIR" ; fi done export PATH unset _DIR }
Here you set PATH to /sbin:/bin if it is unset. You can invoke this function as follows:
SetPath /sbin /usr/sbin /bin /usr/bin /usr/ccs/bin
It checks to see whether each of its arguments is a directory, and if a directory exists, it is added to PATH.
The functions seen thus far operate independently of one another, but in most shell scripts functions either depend on or share data with other functions.
In this section you will look at an example where three functions work together and share data.
The C shell, csh, provides three commands for quickly moving around in the UNIX file system:
These commands maintain a stack of directories internally and enable the user to add and remove directories from the stack and list the contents of the stack.
For those readers who are not familiar with the programming concept of a stack, you can think of it as a stack of plates: you can add or remove a plate only at the top of the stack. You can access only the top plate, not any of the middle plates in the stack. A stack in programming terms is similar. You can add or remove an item only at the top of the stack.
In csh, the stack is maintained within the shell, but in your shell functionbased implementation you have to maintain the stack as an exported environment variable so that all three functions have access to it.
Use the variable _DIR_STACK to store the directory stack. Each entry in the stack is separated by the : character similar to the PATH variable. By using this character rather than a space or tab, you increase the flexibility of the directory names that you can handle.
Previous | Table of Contents | Next |