From owner-freebsd-questions@FreeBSD.ORG Sun Feb 8 23:30:45 2009 Return-Path: Delivered-To: freebsd-questions@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 10F14106564A for ; Sun, 8 Feb 2009 23:30:45 +0000 (UTC) (envelope-from cwhiteh@onetel.com) Received: from honeysuckle.london.02.net (honeysuckle.london.02.net [87.194.255.144]) by mx1.freebsd.org (Postfix) with ESMTP id 9A5F28FC13 for ; Sun, 8 Feb 2009 23:30:44 +0000 (UTC) (envelope-from cwhiteh@onetel.com) Received: from [192.168.1.75] (93.97.24.219) by honeysuckle.london.02.net (8.5.016.1) id 497A2AF0002E0C39; Sun, 8 Feb 2009 23:30:27 +0000 Message-ID: <498F6B12.5000307@onetel.com> Date: Sun, 08 Feb 2009 23:30:26 +0000 From: Chris Whitehouse User-Agent: Thunderbird 2.0.0.19 (X11/20090113) MIME-Version: 1.0 To: Jonathan McKeown References: <332f78510902040635k6675a9b6u434879b42c66a579@mail.gmail.com> <498B8A7F.2060906@onetel.com> <200902081412.15509.jonathan+freebsd-questions@hst.org.za> In-Reply-To: <200902081412.15509.jonathan+freebsd-questions@hst.org.za> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-questions@freebsd.org Subject: Re: shell commands - exclusion X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 08 Feb 2009 23:30:45 -0000 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@pcbsd% find . > > (No expression). Find adds a -print, so this is the same as the next one: > >> chrisw@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@pcbsd% find . -print -o -prune dir1 >> find: dir1: unknown option > > -prune doesn't take an argument, so dir1 is a syntax error. > >> chrisw@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@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@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@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-questions > To unsubscribe, send any mail to "freebsd-questions-unsubscribe@freebsd.org" > Thank you for this excellent answer! Now reading the man page begins to make sense. Chris