I found myself needing to search up the directory tree for a specific file recently, much like git
does to find the .git
directory above it or rbenv does to find the .ruby-version
file that will tell it which Ruby runtime to use. It wasn’t as simple to figure out as I expected.
Here’s the shell function I ended up with:
findup() {
_path=$(pwd)
while [[ "$_path" != "" ]]; do
if [[ -e "$_path/$1" ]]; then
echo "$_path/$1"
return 0
else
_path=${_path%/*}
fi
done
return 1
}
The first few lines of this should be pretty obvious: I’m defining a function, then setting a variable, _path
, to the current working directory. Then I enter a loop as long as _path
doesn’t equal an empty string.
Next, in the if
statement, I look to see if the file I’m looking for is in the current directory. If so, I print its location and exit with 0, which is the exit status for success in Unix-based operating systems.
The else
part of the if
statement is the only tricky part about this little function. I’m using Bash parameter substitution. When I use the ${var}
form to access a variable, I get its value back. I can add to this form to manipulate the return value. Using the ${var%pattern}
form, I remove from the end of ${var}
the shortest part that matches my pattern. My pattern in this case is /*
, which is going to match everything from the last slash forward; in other words, it will remove the last part of _path
, leaving me with the parent directory.
If I get to the root directory (/
) and haven’t found the file I’m looking for, I return 1 to let any program using this function that I exited unsuccessfully, in proper Unix fashion.
Drop that function in your .bashrc
or .zshrc
and you can use it too.