Quantcast
Channel: User Kamil Maciorowski - Super User
Viewing all articles
Browse latest Browse all 645

Answer by Kamil Maciorowski for shell helper function wrapping `find` and ignoring some dirs

$
0
0

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.
  • 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:

  1. In an invocation of find, first there may be options, arguments starting with -. Portable options are -H and -L. Implementations may introduce other options.

  2. Then there are paths. Some implementations of find work well when the number of paths is zero (e.g. GNU find uses . as the default).

  3. 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).


Viewing all articles
Browse latest Browse all 645

Trending Articles