On Mon, Sep 13, 2010 at 09:55:17AM +0200, Joachim Schipper wrote:
> On Thu, Sep 09, 2010 at 10:15:01PM -0600, Tim Chase wrote:
> > On 09/09/10 20:37, d...@mindrot.org wrote [lightly edited]:
> > > $ touch foo.orig foo.rej
> > > $ find . -type f -name \*.orig -or -name \*.rej
> > > ./foo.orig
> > > ./foo.rej
> > > $ find . -type f -name \*.orig -or -name \*.rej -print
> > > ./foo.rej
> > >
> > > [WTF?!]
> >  
> >  Not a bug, but rather order of operations & short-circuit logic 
> >  evaluation.
> 
> Perhaps we could help other people avoid this misunderstanding by
> changing the last EXAMPLE in find(1) to
> 
> $ find . \( -name \*.jpg -or -name \*.gif \) -print0 | xargs -0r rm
> 
> This would demonstrate proper form, too: use print0 when dealing with
> untrusted filenames (...).

[Please snip bugs@ and Stuart from replies.]

Here are two diffs to find(1).

The first diff changes the last example in find(1). This diff:
- makes it clear that it, in fact, works on all files *under* (not just
  "in") the current working directory;
- adds handling of *.gif files to illustrate ordering;
- changes to -print0 | xargs -0r to illustrate proper form.

The second diff is relative to the first diff, and adds the following
warning to CAVEATS:
    "Using find in combination with xargs(1) requires some care:

        $ find . -name \e*.jpg | xargs rm

    would, given a file *important\n.jpg* (where *\n* is a newline),
    remove *important*. Use the -print0 or -X flags, or use -exec
    instead."

This is already addressed in the man page (e.g. under the description of
-print0 or -X), but many people (including the EXAMPLES) get it wrong;
hopefully the above warning (and the references from the description of
-print and the EXAMPLES section) prevents some people from making this
mistake.

                Joachim

Index: find.1
===================================================================
RCS file: /cvs/src/usr.bin/find/find.1,v
retrieving revision 1.78
diff -u -p -r1.78 find.1
--- find.1      15 Jul 2010 20:51:38 -0000      1.78
+++ find.1      13 Sep 2010 12:29:56 -0000
@@ -525,11 +525,11 @@ ending in a dot and single digit, but sk
 .Pp
 .Dl "$ find /usr/src -path /usr/src/gnu -prune -or -name \e*.[0-9]"
 .Pp
-Find and remove all *.jpg files in the current working directory:
+Find and remove all *.jpg or *.gif files under the current working directory:
 .Pp
-.Dl "$ find . -name \e*.jpg -exec rm {} \e;"
+.Dl "$ find . \e( -name \e*.jpg -o -name \e*.gif \e) -exec rm {} \e;
 or
-.Dl "$ find . -name \e*.jpg | xargs rm"
+.Dl "$ find . \e( -name \e*.jpg -o -name \e*.gif \e) -print0 | xargs -0r rm"
 .Sh SEE ALSO
 .Xr chflags 1 ,
 .Xr chmod 1 ,

--- find.1      Mon Sep 13 14:12:53 2010
+++ find.1.new  Mon Sep 13 14:32:38 2010
@@ -382,7 +382,10 @@
 It prints the pathname of the current file to standard output, followed
 by a newline
 .Pq Ql \en
-character.
+character. This should not be used in conjunction with
+.Xr xargs 1 ,
+see
+.Sx CAVEATS .
 .It Ic -print0
 This primary always evaluates to true.
 It prints the pathname of the current file to standard output, followed
@@ -530,6 +533,13 @@
 .Dl "$ find . \e( -name \e*.jpg -o -name \e*.gif \e) -exec rm {} \e;
 or
 .Dl "$ find . \e( -name \e*.jpg -o -name \e*.gif \e) -print0 | xargs -0r rm"
+.Pp
+Note the use of
+.Ic -exec
+or
+.Ic -print0 ;
+see
+.Sx CAVEATS .
 .Sh SEE ALSO
 .Xr chflags 1 ,
 .Xr chmod 1 ,
@@ -637,6 +647,26 @@
 and
 .Ql \&;
 may have to be escaped from the shell.
+.Pp
+Using
+.Nm
+in combination with
+.Xr xargs 1
+requires some care:
+.Pp
+.Dl "$ find . -name \e*.jpg | xargs rm"
+.Pp
+would, given a file
+.Pa important\en.jpg
+(where \en is a newline), remove
+.Pa important .
+Use the
+.Ic -print0
+or
+.Ic -X
+flags, or use
+.Ic -exec
+instead.
 .Pp
 As there is no delimiter separating options and file names or file
 names and the

Reply via email to