shell commands - exclusion
Chris Whitehouse
cwhiteh at onetel.com
Sun Feb 8 15:30:45 PST 2009
Jonathan McKeown wrote:
> On Friday 06 February 2009 02:55, Chris Whitehouse wrote:
>> I think you should be able to do it with a combination of -prune and
>> -delete (or -exec rm -rf {} \; ) on a find command. Substitute your
>> other commands for rm -rf in the -exec above.
>>
>> I would give you a working example except I can't figure out the syntax
>> for -prune. Examples from google don't seem to work in (my) FreeBSD.
>
> [skip to the end for a simple answer without the lengthy exposition]
>
> find(1) can be confusing, especially if you think of the ``actions''
> ( -print, -exec and -delete plus their variants like -ls and -ok ) as
> something different from the ``tests'' ( -name and so on), or if you don't
> take account of the evaluation order.
>
> A find expression comprises a number of what the manpage calls primaries, each
> of which evaluates as true or false. (It may also have a side-effect,
> like -print whose side-effect is to print the name). Primaries can be
> combined with -and (which is usually implied) or -or. Where -and and -or both
> occur, find will group the -anded primaries together before evaluation.
> Taking one of your examples below,
>
> find . -print -or -prune -name dir1
>
> this is grouped as
>
> find . -print -or \( -prune -and -name dir1 \)
>
> find will then evaluate the whole expression from left to right for each
> pathname in the tree it's looking at, stopping within each set of (implied)
> parentheses and within the overall expression as soon as it can determine
> truth or falsehood. (This is what's referred to in programming as
> short-circuiting in boolean expressions).
>
> If primaries are linked by -and, find can stop at the first one that's false,
> knowing the expression is false; if they're linked by -or it can stop at the
> first one that's true, knowing the expression is true. Otherwise it has to
> evaluate the whole expression.
>
> Before it does this, though, find checks for side-effects. If there isn't a
> side-effect anywhere in your expression, find will put brackets round the
> whole expression and a -print after it.
>
> Looking at your examples:
>
>> chrisw at pcbsd% find .
>
> (No expression). Find adds a -print, so this is the same as the next one:
>
>> chrisw at pcbsd% find . -print
>> .
>> ./test.mov
>> ./test.mpg
>> ./dir1
>> ./dir1/file1
>> ./dir1/file2
>> ./file3
>
> -print is always true so the expression is true for each name - they get
> printed as a side-effect.
>
>> chrisw at pcbsd% find . -print -o -prune dir1
>> find: dir1: unknown option
>
> -prune doesn't take an argument, so dir1 is a syntax error.
>
>> chrisw at pcbsd% find . -print -o -prune -name dir1
>
> find evaluates the print, which prints each name as its side-effect. -print
> evaluates as true. Since it's in an -or, find can stop there, so it never
> sees the second expression ( -prune -and -name dir1: the -and is implicit).
>> .
>> ./test.mov
>> ./test.mpg
>> ./dir1
>> ./dir1/file1
>> ./dir1/file2
>> ./file3
>
>> chrisw at pcbsd% find . -print -o -name dir1 -prune
>
> Same again: find stops after the -print which is always true, and ignores
> the -name dir1 -and -prune.
>
>> chrisw at pcbsd% find . -name "*" -o -name dir1 -prune
>
> None of these primaries has a side-effect, so find rewrites this internally as
>
> find . \( -name "*" -or -name dir1 -prune \) -print
>
> -name "*" is always true, so find can ignore everything after the -or up to
> the parenthesis. Because the first expression is true, and the parens are
> followed by (an implied) -and, find has to evaluate the -print, which is
> always true, so the whole expression is always true and it always prints the
> name as a side-effect.
>> .
>> ./test.mov
>> ./test.mpg
>> ./dir1
>> ./dir1/file1
>> ./dir1/file2
>> ./file3
>
> What you need is an expression with two outcomes: a -prune for some names and
> a -print for others. That tells you you need an -or, and the -print must come
> after it because it's always true. Before the -or, -prune is always true so
> you need some sort of testing primary before the -prune.
>
> That gives you
>
> find . -name dir1 -prune -or -print
>
> Jonathan
> _______________________________________________
> freebsd-questions at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-questions
> To unsubscribe, send any mail to "freebsd-questions-unsubscribe at freebsd.org"
>
Thank you for this excellent answer! Now reading the man page begins to
make sense.
Chris
More information about the freebsd-questions
mailing list