1 Finding Programs in the PATH

#1 Finding Programs in the PATH

Shell scripts that use environment variables (like MAILER and PAGER) have a hidden danger: Some of their settings may well point to nonexistent programs. For example, if you decide to be flexible by using the PAGER setting to display script output, instead of just hard-coding a specific tool, how do you ensure that the PAGER value is set to a valid program? After all, if it's not a valid program, your script will break. This first script addresses how to test whether a given program can be found in the user 's PATH, and it's also a good demonstration of a number of different shell scripting techniques, including script functions and variable slicing.

The Code

 #!/bin/sh # inpath - Verifies that a specified program is either valid as is, #   or that it can be found in the PATH directory list. in_path() {   # Given a command and the PATH, try to find the command. Returns   # 0 if found and executable, 1 if not. Note that this temporarily modifies   # the IFS (input field separator) but restores it upon completion.   cmd=        path=         retval=1   oldIFS=$IFS   IFS=":"   for directory in $path   do     if [ -x $directory/$cmd ] ; then       retval=0      # if we're here, we found $cmd in $directory     fi   done   IFS=$oldIFS   return $retval } checkForCmdInPath() {   var=   # The variable slicing notation in the following conditional   # needs some explanation: ${var#expr} returns everything after   # the match for 'expr' in the variable value (if any), and   # ${var%expr} returns everything that doesn't match (in this   # case, just the very first character. You can also do this in   # Bash with ${var:0:1}, and you could use cut too: cut -c1.   if [ "$var" != "" ] ; then     if [ "${var%${var#?}}" = "/" ] ; then       if [ ! -x $var ] ; then         return 1       fi     elif ! in_path $var $PATH ; then       return 2     fi   fi } 
Where to put your scripts  

I recommend that you create a new directory called "scripts," probably as a part of your HOME directory, and then add that fully qualified directory name to your PATH variable. (Use echo $PATH to see your current PATH, and edit the contents of your .login or .profile (depending on the shell) to modify your PATH appropriately.)

Running the Script

To run this script, we first need to append a short block of commands to the very end of the file. These commands pass a starting parameter to the validation program and check the return code, like so:

 if [ $# -ne 1 ] ; then  echo "Usage: 
 if [ $# -ne 1 ] ; then echo "Usage: $0 command" >&2 ; exit 1 fi checkForCmdInPath "$1" case $? in 0 ) echo "$1 found in PATH" ;; 1 ) echo "$1 not found or not executable" ;; 2 ) echo "$1 not found in PATH" ;; esac exit 0 
command" >&2 ; exit 1 fi checkForCmdInPath "" case $? in 0 ) echo " found in PATH" ;; 1 ) echo " not found or not executable" ;; 2 ) echo " not found in PATH" ;; esac exit 0

Once you've added the additional code snippet, you can invoke this script directly, as shown in "The Results," next . Make sure to remove or comment out the additional code before you're done with this script, however, so its later inclusion as a library function doesn't mess things up.

The Results

To test the script, let's invoke inpath with the names of three programs: a program that exists, a program that exists but isn't in the PATH, and a program that does not exist but that has a fully qualified filename and path:

 $  inpath echo  echo found in PATH $  inpath MrEcho  MrEcho not found in PATH $  inpath /usr/bin/MrEcho  /usr/bin/MrEcho not found or not executable 

Hacking the Script

Perhaps the most unusual aspect of this code is that it uses the POSIX variable slicing method of ${var%${var#?}} . To understand this notation, realize that the apparent gobbledygook is really two nested string slices. The inner call, ${var#?} , extracts everything but the first character of the variable var ( ? is a regular expression that matches one character). Next, the call ${var%pattern} produces a substring with everything left over once the specified pattern is applied to the inner call. In this case, what's left is the first character of the string.

This is a pretty dense explanation, admittedly, but the key to getting check- ForCmdInPath to work is for it to be able to differentiate between variables that contain just the program name (like echo ) and variables that contain a full directory path plus the filename (like " /bin/echo "). It does this by examining the very first character of the given value to see if it's a " / " or not; hence the need to isolate the first character from the rest of the variable value.

If this POSIX notation is too funky for you, Bash and Ksh support another method of variable slicing. The substring function ${varname:start: size } requests a certain number of characters from varname specified by size and beginning with the character number in varname specified by start . For example, ${varname:1:1} would produce a substring consisting of just the first character of varname . Of course, if you don't like either of these techniques for extracting just the first character, you can also use a system call: $(echo $var cut -c1) .


Script #47 in the Administrative Tools chapter is a useful script that's closely related to this one. It validates both the directories in the PATH and the environment variables in the user's login environment.

Wicked Cool Shell Scripts. 101 Scripts for Linux, Mac OS X, and Unix Systems
Wicked Cool Shell Scripts
ISBN: 1593270127
EAN: 2147483647
Year: 2004
Pages: 150
Authors: Dave Taylor

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net