I have a source code tree whose root is at something like /home/me/workspace
. There are many subdirectories many levels deep. In particular there is a path containing some tools:
/home/me/workspace/tools/scripts
I am writing a bash function which I can call from any place in the tree to which I pass the string tools/scripts
. The function should iterate its way from the present working directory to /
looking for path fragment tools/scripts
, then if it finds it, print out the absolute path in which it is found. In this example, /home/me/workspace
would be printed. If the path fragment is not found at all, then nothing is printed.
I already have the following bash function which does this for me:
search_up ()
(
while [ $PWD != "/" ]; do
if [ -e "$1" ]; then
pwd
break
fi
cd ..
done
)
but this seems a bit long-winded. I am wondering if there are any other ways to do this either in bash itself, or in perhaps a single find
command, or any other common utility. I'm particularly looking for readability and brevity.
Note I am not looking for a full recursive search of the entire tree.
Also my bash is not the latest, so please no tricks using the latest, greatest:
$ bash --version
GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2004 Free Software Foundation, Inc.
$
This should work but tell me if it needs compatibility with POSIX. The advantage of this is that you don't need to change your directory to higher level just to make the search, and also no need to use a subshell.
#!/bin/bash
search_up() {
local look=${PWD%/}
while [[ -n $look ]]; do
[[ -e $look/$1 ]] && {
printf '%s\n' "$look"
return
}
look=${look%/*}
done
[[ -e /$1 ]] && echo /
}
search_up "$1"
Example:
bash script.sh /usr/local/bin
Output:
/
For the record, here is what I ended up using:
while [ $PWD != "/" ]; do test -e tools/bin && { pwd; break; }; cd .. ; done
Similar to my OP, but in the end I was able to drop the subshell parentheses () completely, because this line is itself invoked using the "shell" command from another program. Hence also stuffing it all onto one line.
I still liked KonsoleBox's well-reasoned answer as a possibly more general solution, so I'm accepting that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With