Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

If I have a colon-separated path list, much like $PATH, but not neccessarily $PATH.

I want to search that list for a specific file name. However, I only want the first matching path.

I have considered the following linux commands:

  • which: only works for binary, and only works with $PATH variable
  • whereis: works with particular kinds of files, and only works with $PATH variable
  • find: does not support colon-separated path lists, and returns multiple results

Here are some things I have tried:

  1. I have tried to use whereis by the following strategy

    env WHEREIS="`which whereis`" PATH="$MY_PATH_LIST" $WHEREIS "$TARGET_FILE"
    

    and this almost works. However, it does not seem to return results for arbitrary file types. It also returns multiple results, and in an awkward format.

  2. I could get which to work by

    env WHICH="`which which`" PATH="$MY_PATH_LIST" $WHICH "$MY_TARGET_FILE"
    

    if there was a command-line option to force it to allow non-executables.

  3. I then tried to solve the problem with find. First I used regular expressions to expand the path list (I replace colons with spaces). Then I invoke find, and it works correctly. However, it searches all of the paths. I cannot seem to find a way to tell it to stop the search early if it finds a good result.

    I did get this to work

     find ${MY_PATH_LIST//[:]/ } -name "$MY_TARGET_FILE" | head -n 1
    

    but it takes a long time to complete, because find is still doing an exhaustive search.

    I need this to execute faster (exit on first result), because it would be run many times, with different parameters.

Does anyone have a better solution to suggest?

Note that if all fails, I can write a non-bash solution. Write now I'm hoping for a simple solution using existing tools.

share|improve this question
add comment

1 Answer

up vote 3 down vote accepted

You could just use a script that simply tests (-e) for existence of a file and stops when the first one has been found:

#!/bin/bash
[[ $# -gt 0 ]] || { echo "Usage: $0 <filename> [pathspec]" >&2 ; exit 1 ; }
if [[ $# -gt 1 ]] ; then
        P="$2"
else
        P="$PATH"
fi

IFS=:
for DIR in $P ; do
        if [[ -e "$DIR/$1" ]] ; then
                echo "$DIR/$1"
                exit 0
        fi
done

Example:

$ ./search.sh 
Usage: ./search.sh <filename> [pathspec]

$ ./search.sh ls
/Users/danielbeck/bin/ls

$ ./search.sh pwd
/bin/pwd

$ ./search.sh ls /bin
/bin/ls

$ ./search.sh ls /usr/bin:/bin
/bin/ls
share|improve this answer
    
Thanks, Daniel. This works. I am surprised that there isn't a built-in command for this purpose. I'm going to wait a bit to see if there are any interesting comments. So far, it looks like this one will be going to you. :-) –  Kevin A. Naudé Dec 20 '12 at 11:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.