Here’s another incredibly useful bit of shell. Everyone knows how useful the
find
command is, but probably doesn’t use it as much as they should, because
the syntax is a little odd and picky. Here’s my attempt to simplify it for
common interactive uses.
It’s based on three observations:
- The most common thing I do with
find
isfind ‑name \*foo\*
. - When I pass directory names to
find
, I almost always tab-complete them, and when I do that, bash inserts a slash. - I often add stuff to the end of a previous command, like
‑print0
, but sometimes I want to add a directory also.
So, this little wrapper around find
looks at each arg and does one of three
things: If it has a slash in it, it’s a directory and it goes at the front of
the final command line. If it starts with a dash, it’s flag, and it goes at the
end. Everything else is a substring to search for in a filename.
That’s it. The only tricky feature is when you want to pass an argument to a
flag, and not have it interpreted as a substring match. To handle that, flags
are deliberately double-expanded, so you can escape the space like
ff foo ‑mtime\ 0
.
ff () {
local IFS=$' \t\n'
local -a args
local -a names
local -a paths
local dasho=''
local d
for d; do
case "$d" in
# let this get expanded
-*) args+=($d) ;;
# quote this
*/*) paths+=("$d") ;;
# process this into a partial find expression
*) names+=($dasho -name "*$d*"); dasho='-o' ;;
esac
done
find "${paths[@]}" \( "${names[@]}" \) "${args[@]}"
}