views:

1409

answers:

2

Which one is more efficient over a very large set of files and should be used?

find . -exec cmd {} +

or

find . | xargs cmd

(Assume that there are no funny characters in the filenames)

+1  A: 
find . | xargs cmd

is more efficient (it runs cmd as few times as possible, unlike exec, which runs cmd once for each match). However, you will run into trouble if filenames contain spaces or funky characters.

The following is suggested to be used:

find . -print0 | xargs -0 cmd

this will work even if filenames contain funky characters (-print0 makes find print NULL-terminated matches, -0 makes xargs expect this format.)

ASk
This is not"find . -exec cmd {} \;"but"find . -exec cmd {} +". The latter will not run one file at a time.
Tometzky
+4  A: 

Speed difference will be insignificant.

But you have to make sure that:

  1. Your script will not assume that no file will have no space, tab, etc in file name; the first version is safe, the second is not.

  2. Your script will not treat a file starting with "-" as an option.

So your code should look like this:

find . -exec cmd -option1 -option2 -- {} +

or

find . -print0 | xargs -0 cmd -option1 -option2 --

The first version is shorter and easier to write as you can ignore 1, but the second version is more portable and safe, as "-exec cmd {} +" is a relatively new option in GNU findutils (since 2005, lots if running systems will not have it yet) and it was buggy recently. Also lots of people do not know this "-exec cmd {} +", as you can see from other answers.

Tometzky
-print0 is also a GNU find (and GNU xargs) option which is missing from a lot of non-Linux systems, so the portability argument isn't as valid. Using just -print and leaving the -0 off of xargs, however, *is* very portable.
dannysauer
The point is that without -print0 it does not work if there is a file with a space or tab etc. This can be a security vulnerability as if there is a filename like "foo -o index.html" then -o will be treated as an option. Try in empty directory: "touch -- foo\ -o\ index.html; find . | xargs cat". You'll get: "cat: invalid option -- 'o'"
Tometzky