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