Tuesday, October 23, 2007
2:41 AM

The find / xargs Linux command-pipe

My task at hand is to delete all backup files ("*~") located anywhere in my home directory hierarchy.

$ find /home/peter -name *~ |xargs rm

This works reasonably well, but some targeted backup files are actually not deleted, namely:
  1. backup files in a sub-directory that is symbolically linked.
  2. backup files that have spaces in their file name or path name.

In addition, the xargs command handles zero argument poorly. If no match is found by the find command, xargs is not smart enough to terminate right away, but will still try to execute the target command (rm) in some way.

$ find /home/peter -name no-such-thing* |xargs rm
rm: missing operand


Symbolic Links

find does not follow symbolic links, by default. To make it follow symbolic links, add the -L parameter.

$ find -L /home/peter -name *~ |xargs rm

Names with spaces

xargs splits up its input arguments at spaces (and newlines). If a file name (or path name) has spaces in it, e.g., "can not do this.pdf", xargs will misinterpret it and thinks there are multiple files.

The solution is to invoke xargs with the -0 (zero) parameter. xargs will separate filenames by NUL instead of whitespace. Also, the find command needs the -print0 parameter: this puts a NUL between filenames instead of a newline.

Note that the -print0 parameter must be put last in find.
$ find /home/peter -name *~ -print0 |xargs -0 rm


Zero argument

Use the -r flag with xargs. If stdin is empty, xargs will not run the command, and exit.

Putting it altogether, the command I will use for my task is:

$ find -L /home/peter -name *~ -print0 |xargs -0 -r rm

P.S. As a comment rightly pointed out, I do not need xargs to achieve the same result. Instead of xargs, I could have used the -exec argument of find:
$ find -L /home/peter -name *~ -exec rm {} \;

However, "find|xargs" is more efficient than "find -exec". See this explanation.

StumbleUpon Toolbar

0 comments:

Post a Comment