Find: -exec vs xargs (aka Why does “find | xargs basename” break?)

command linefindgnuxargs

I was trying to find all files of a certain type spread out in subdirectories, and for my purposes I only needed the filename. I tried stripping out the path component via basename, but it did't work with xargs:

$ find . -name '*.deb' -print | xargs basename 
basename: extra operand `./pool/main/a/aalib/libaa1_1.4p5-37+b1_i386.deb'
Try `basename --help' for more information.

I get the same thing (exactly the same error) with either of these variations:

$ find . -name '*.deb' -print0 | xargs -0 basename 
$ find . -name '*.deb' -print | xargs basename {}

This, on the other hand, works as expected:

$ find . -name '*.deb' -exec basename {} \;
foo
bar
baz

This happens on up-to-date Cygwin and Debian 5.0.3. My diagnosis is that xargs is for some reason passing two input lines to basename, but why? What's going on here?

Best Answer

Because basename wants just one parameter... not LOTS of. And xargs creates a lot of parameters.

To solve your real problem (only list the filenames):

 find . -name '*.deb' -printf "%f\n"

Which prints just the 'basename' (man find):

 %f     File's name with any leading directories
        removed (only the last element).
Related Question