Writing a shell script (in bash and fish) to recursively call the find unix command in parent directories.
Table of contents
Intro
In my workflow I use a command I have named upfind
to recursively search
upwards in directories till the query is matched. I commonly use this to jump to
the root directory of my current project, or things similiar to that. Below I
will describe how to make this command, in bash and then source it to your
machine. Then I will provide an alternative method to writing it in fish,
which will have completions, and be automatically sourced to your machine. If
you think having a command like this would be useful in your dev toolkit, feel
free to follow along below.
Bash
As you fill find throughtout many of my other blog posts, I highly recommend a out the fish shell if you are not already. However, below I document how to create this command in bash.
Creating the upfind command
To create an upfind
command for your dev enviornment, we begin by running the
following commands.
touch upfind && chmod +x upfind
Next we open the file in your editor of prefrence, and copy and paste the following snippet.
#!/bin/bash
while [[ $PWD != / ]]; do
if test $(find "$PWD"/ -maxdepth 1 "$@" | wc -c) -eq 0
then
cd ..
else
echo $PWD;
break;
fi
done
Using the upfind command
./upfind -name $HOME
Moving the command into your path
You will want to then move this file into your $PATH
, to allow it to be
executed by your user. You can see which directories are currently sourced to
your user, by echoing the $PATH
variable in your shell language of choice.
It is typically recommened to move your user executables into the following
directory: ~/.local/bin/
However, you can also place files into the directory /usr/bin/
or
/usr/bin/local/
. This could create issues though, as the executables found in
these paths are system commands.
Using the bash ‘upfind’ command
After placing the ./upfind
command in your $PATH
you can call the command as
you would any other shell command.
Fish
To write the command in fish-shell the shell code is not very different. The main pro to writing this command in fish, that we can provide completions to the command with relative ease as well.
Creating the upfind command
To create an upfind
command for your fish shell dev enviornment, we begin by
creating a file in one of the directories auto-sourced by $fish_function_path
.
I will assume you are using the default path, so create a file named upfind
by
using the following command:
touch ~/.config/fish/functions/upfind.fish
Writing upfind in fish shell
After you have created the upfind
file, open your editor and enter the code
below. This code is working in fish, version 3.6.1
:
function upfind --wraps find --description "find recursively upwards"
while [ $PWD != / ]
if test $(find "$PWD"/ -maxdepth 1 $argv | wc -c) -eq 0
cd ..
else
echo $PWD
break;
end
end
end
Lets break down some of the nuances in syntax used above.
- Passing the flag
--wraps
to thefunction
command, wraps all completions to the commandfind
to our new commandupfind
. - If we place this file in our
~/.config/fish/functions
it is automatically sourced to our entire shell. - Using the
[ ]
syntax we are effectively calling thetest
command in fish shell. I first found out that these were syntacic equals from browsing through the tree-sitter-fish repo.
Using your new upfind command:
After you have picked a shell to implement this script, you should be able to
use the upfind
command however you may need it. Personally, I recommend the
fish implementation because of its ease of use, as well as it’s ability to
give me completions.
Examples
I use the upfind
command for various cases daily but some of which can be
found below:
- finding the parent
.git/
directory:upfind -name .git
- finding the parent directory to a
package.json
file:upfind -name package.json