2

More silly questions from the Linux n00b. =D

I'm curious about the performance ramifications of using xargs vs. backticks.

For example, what's the different between:

find ./ -name foo* | xargs rm

and

rm `find ./ -name foo*`

It seems to me that it would be a better practice to pipe and use xargs as stuff could be processed in sequential order.

Your thoughts?

-M

2
  • note these commands are basically the same thing -- xargs runs one rm with the piped-in input as arguments. John T's answer shows how to run one rm for each file found. Nov 3, 2009 at 4:02
  • 1
    they are not 'basically' the same: xargs runs as many 'rm's as it needs to run to handle all given filenames. to quote 'man xargs': "... and executes the command (default is /bin/echo) one or more times ..." . the backtick solution instead expands the output of find on the commandline and then it runs only ONE rm, plus you might get problems with the number of arguments reaching maximum (see chris answer).
    – akira
    Nov 3, 2009 at 10:19

3 Answers 3

2

Backticks hurt when dealing with more complex scripting; you need to carefully escape backticks contents. Because of that I often change them into $(...).

xargs might call rm multiple times in your example if there is lots of files -- POSIX systems can have upper limit on length of command parameters.

xargs has other features that backticks doesn't: f.e. xargs can take parameters separated by \0 byte to deal with filenames with spaces.

2

If you are dealing only with a few pathnames that do not contain whitespace, then they are equivalent.

On some systems, the maximum length of a single command-line (actually, environment plus arguments sent to an exec(2)-family call) is limited (see kern.argmax). On a limited system, if find produces too much output, the shell would not be able to fit it all into the surrounding command line. To fix this, xargs takes the output of find and combines the ‘words’ (yes, words, not lines, see below) into groups that fit into a single command-line.

Second, both xargs and the shell (via backticks) will split up find's output into arguments for rm by tokenizing the output at every run of any combination of space, tab, or newline characters (this is a simplification since they both have their own quoting rules that are close, but not identical). If find -prints a pathname of “.//foo/bar quux”, rm will eventually see two arguments (“.//foo/bar” and “quux”). If a file named quux existed in the cwd from which you started, it would be gone when it was all over (and “.//foo/bar quux” would still be there!).

So the most robust method is to use find's -print0 and xargs's -0 POSIX-extension. Working together, they can be used to robustly transport any legal pathname from the output of find to the command-line of any other command on any system that supports the two extensions.

find . -name foo\* | xargs -0 rm

The robustness comes from the fact that the NUL byte that both extensions use to terminate pathnames is the only disallowed byte in just about all (Unix-oid) OSes.

1

If the program supports multiple arguments in that order, the backticks should perform identically. Since not all programs support multiple arguments like that, the problem arises when a command in backticks is executed and returns multiple results. If you know the latter command will work, use it. If you aren't sure, stick with using xargs to be safe. find also has a useful -exec switch which can be used like so:

find / -type f -exec grep -i word {} +

where the braces are replaced with the current file match from find.

1
  • 2
    find has also a useful -delete switch .. which makes -exec rm '{}' ';' pretty useless ...
    – akira
    Nov 3, 2009 at 10:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .