#!/bin/sh # This script finds executable files on a Unix system by # searching four sources of information: # (i) the user's PATH environment variable, # (ii) the 'whereis' command, # (iii) a path supplied as a parameter and # (iv) the 'locate' command (if available). # # The result is a (space separated) list of directories where the # executable can be found. # Please note that the returned list of directories is not # necessarily in the same order of directories found in the user's # PATH environment variable. (This was done on purpose to reduce # disk i/o, see below.) # The primary advantage with this script is that the can collate # search results from the various search tools provided by Unix. # The second advantage with this script is that duplicate paths # are removed before accessing the disk, thereby reducing disk i/o. # # Example invocation: # findfile tclsh /local/tcl-7.5/bin:/roo/tcl-7.5/bin # Here 'tclsh' is the executable file that we want to find and # the second parameter is a colon-separated path of extra directories # to search. # # Possible improvements: # 1) use 'which' to check for aliases # 2) use 'find' to search a hierarchy # 3) include help page # # Author: Graham Phillips # Date created: 1996 # Last modified: September 1999 findfile () { # A function to search for executable files. # Argument 1: executable file that we want to find # Argument 2: extra directories (not in PATH) to search # Example # findfile tclsh /local/tcl-7.5/bin:/roo/tcl-7.5/bin fname=$1 if [ "$fname" = "" ] ; then exit fi found=0 other_dirs=$2 # First use `whereis`. # Append results to f_list. # All our list contains entries separated by spaces. list=`whereis -b $fname 2>/dev/null` ff_list=`echo $list | sed 's/..*:[ ]*\(.*\)/\1/g'` f_list="" if [ "$ff_list" != "" ] ; then for i in $ff_list ; do f_list="$f_list "`echo $i | sed 's/\(..*\)\/[^\/][^\/]*/\1/g'` done fi # Next, try `locate`, which is typically found on FreeBSD systems. # This step can be time-consuming. paths=`which locate 2> /dev/null` l_list="" if test -x $paths 2> /dev/null; then l_list=`locate $fname 2> /dev/null` for i in $l_list ; do # check if the name after the last '/' is $fname # strip everything up to the last '/' j=`echo $i | sed 's/.*\///g'` if [ "$j" = "$fname" ]; then l_list="$l_list $j" fi done fi # Next, use PATH environment variable and parameter passed in. # Append results to u_list. paths="$f_list $l_list"`echo $PATH:$other_dirs | sed 's/\(:\)/ /g'` u_list="" for i in $paths ; do # remove trailing / in dir j=`echo $i | sed 's/\/$//g'` u_list="$u_list $j" done # Next, sort and remove duplicates. # Results put in e_list. s_list=`echo $u_list | tr ' ' '\012' | sort | uniq` e_list="" for i in $s_list ; do if test -x ${i}/$fname ; then e_list="$e_list $i" fi done if [ "$e_list" != "" ] ; then echo $e_list fi } findfile $* exit