The following function will convert each argument being exactly -exclude_hazards
to arguments responsible for the desired exclusions:
my_find () (#!/bin/shmark=for arg do [ -z "$mark" ] && { set --; mark=y; } case "$arg" in -exclude_hazards ) set -- "$@" \! \( \ \( \ -path './_output' \ -o -path './release' \ -o -path './target' \ -o -path '*/third_party/*' \ -o -path '*/vendor/*' \ \) -prune \ \) ;; * ) set -- "$@" "$arg" ;; esacdoneexec find "$@")
Usage:
my_find . -exclude_hazards -type f -name '*.foobar' -print0
This is not exactly what you wanted, but the implementation is simple, without any need for knowing the meaning of other arguments. In other words the function does not have to parse other arguments and classify them as options/paths/expression in order to inject extra code*. You explicitly put -exclude_hazards
in the right place and there is no ambiguity, no guessing, no dependency on some particular implementation of find
. KISS!
Note my_find . -exclude_hazards -exec echo -exclude_hazards \;
will convert both occurrences of -exclude_hazards
. I could make the function convert only the first occurrence, but since I don't expect this quirk to be a problem in practice, I decided not to complicate the code. Besides, the fixed function would still misbehave for my_find . -exec echo -exclude_hazards \;
. In my opinion this is a reasonable price for KISS.
Notes:
The shell code is portable.
I wanted the solution to work with virtually any implementation of
find
, therefore- I changed your non-portable
-not
to equivalent portable!
; - I changed your non-portable
-wholename
to equivalent portable-path
.
- I changed your non-portable
What looks like a shebang is just a comment, it will be ignored when the function gets created. I put it there, so you can copy the whole body of the function, paste into a regular file and make the file a standalone script; the line will become a shebang then, possibly no adjustment will be required.
* Classifying arguments as options/paths/expression is possible only if you know exactly what your find
is. Consider this:
In an invocation of
find
, first there may be options, arguments starting with-
. Portable options are-H
and-L
. Implementations may introduce other options.Then there are paths. Some implementations of
find
work well when the number of paths is zero (e.g. GNUfind
uses.
as the default).Finally an argument (if any) that starts with a
-
, or is a!
or a(
is the beginning of an expression made up of primaries and operators. There may be no such argument, the expression may be empty. Implementations may support non-portable primaries and/or operators.
This means find -X …
may be a valid command that works with some (future, custom) implementation of find
, but we cannot know in advance if -X
is an option or the beginning of an expression. There is no way to tell, unless you know how this find
will treat it. Our simple function does not try to guess, it's the user who should know and use either my_find -X -exclude_hazards …
(-X
is an option) or my_find -exclude_hazards -X …
(-X
was the beginning of the expression).