Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

So say I'm in a directory that is deep within a file structure, such as

/home/cory/projects/foo/bar/bash/baz

I know that in either the current folder baz or one of the folders above me (such as home, cory, projects, foo, bar, or bash) there is a file named happy. How can I find that file without searching a lot of extra folders?

share|improve this question
    
possible duplicate of find searching in parent directories instead of subdirectories –  Gilles May 19 '11 at 22:44
add comment

3 Answers

up vote 8 down vote accepted
#!/bin/bash

function upsearch () {
    test / == "$PWD" && return || test -e "$1" && echo "found: " "$PWD" && return || cd .. && upsearch "$1"
}

This function will walk up from the current dir. Note, that it is a function, and will change the directory, while traversing. It will stop in the directory, where it finds the file, and will walk up to the root / if not.

You might want to change it to a script instead of a function, and maybe jump back, if the file isn't found in the root directory.

If you never want to cd to the dir:

upsearch () {
  slashes=${PWD//[^\/]/}
  directory="$PWD"
  for (( n=${#slashes}; n>0; --n ))
  do
    test -e "$directory/$1" && echo "$directory/$1" && return 
    directory="$directory/.."
  done
}

This will lead to results like /home/cory/a/b/c/../../../happy if the file is in /home/cory/. If you need a cleaned path, you could do some

cd "$directory"
echo "$PWD"
cd - 

on success.

share|improve this answer
    
Remember to quote your expansions. If $PWD has a space in your test will be broken by wordsplitting. –  Chris Down Sep 20 '11 at 15:50
    
I added masking to the directories. Is it correct now? It will still fail with special characters like '*' in filenames, won't it? –  user unknown Sep 21 '11 at 2:41
add comment

Take a look at the -mindepth and -maxdepth options to find.

find won't traverse directories in a backwards direction, but you can approach it in the regular direction and limit the depth of the search.

For example:

find /home /home/cory /home/cory/projects /home/cory/projects/foo /home/cory/projects/foo/bar /home/cory/projects/foo/bar/bash -maxdepth 0 -name happy -print
share|improve this answer
    
That's not going to help. Either you use -maxdepth 0 or -maxdepth 1, in which case find isn't useful, or you don't, in which case you traverse plenty of extraneous directories for no reason. –  Gilles May 19 '11 at 23:02
    
It is a working solution. I have added an example to clarify this. –  gjb May 19 '11 at 23:21
    
You're missing the step where you generate the list of directories from $PWD or some argument. And if you're going to do that, you don't need find (ok, you can call it, but it won't be very useful). –  Gilles May 19 '11 at 23:24
    
The question was "How can I find that file without searching a lot of extra folders?". I accept that this might not be the most elegant solution, but it gets the job done without searching any extra folders. –  gjb May 19 '11 at 23:32
add comment

I improved on @user-unknown's solution a bit by saving the current dir, performing an arbitrary test, then restoring the original dir before returning with response. It's more flexible because you can test for anything.

I also provide for an optional second argument that says how high to go.

https://gist.github.com/1577473

#!/bin/bash

# Use this script instead of ~/.rvm/bin/rvm-prompt
# and the output of rvm-prompt will show up in your command prompt
# only if you are in a Ruby project directory.

# see http://stackoverflow.com/a/4264351/270511
# and http://unix.stackexchange.com/questions/13464/is-there-a-way-to-find-a-file-in-an-inverse-recursive-search

upsearch () {
  the_test=$1
  up_to=$2
  curdir=`pwd`
  result=1

  while [[ "`pwd`" != "$up_to" && "`pwd`" != '/' ]]; do
    if eval "[[ $the_test ]]"; then
      result=0
      break
    fi
    cd ..
  done
  cd $curdir
  return $result
}

if upsearch '-e Gemfile || ! -z "$(shopt -s nullglob; echo *.gemspec *.rb)"' ; then
  ~/.rvm/bin/rvm-prompt
fi
share|improve this answer
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.