455

I'm trying to understand the difference between these two commands:

find / -name .DS_Store -delete

and

find / -name ".DS_Store" -exec rm {} \;

I noticed that the -exec ... {} method is preferred. Why? Which one is safer/faster/better? I've used both on my Macbook and everything appears to work well.

0

4 Answers 4

456

-delete will perform better because it doesn't have to spawn an external process for each and every matched file, but make sure to call this option after the filtering criteria (i.e. -name, -cmin, -type, etc.), otherwise it will delete the specified entire file tree. Indeed, quoting the find manpage :

GNU find searches the directory tree rooted at each given starting-point by evaluating the given expression from left to right, according to the rules of precedence (see section OPERATORS), until the outcome is known

For example,

find . -name .DS_Store -type f -delete

should be fine.

It is possible that you may see -exec rm {} + often recommended because -delete does not exist in all versions of find. I can't check right now but I'm pretty sure I've used a find without it.

Both methods should be "safe".

A common method for avoiding the overhead of spawning an external process for each matched file is:

find / -name .DS_Store -print0 | xargs -0 rm

(but note that there is a portability problem here too: not all versions of find have -print0!)

9
  • 12
    I see. I've also read that using the -delete switch before -name deletes the specified file tree, so I guess I have to be careful.
    – Onion
    Nov 13, 2014 at 18:56
  • 24
    On recent find you can use -exec rm {} + to remove all matched files with single rm command.
    – jimmij
    Nov 13, 2014 at 18:59
  • 3
    .DS_Store doesn't contain any special characters at all, so the quotes are unnecessary and change nothing in this case.
    – Celada
    Nov 13, 2014 at 19:09
  • 2
    Basically only whitespace (spaces, tabs, maybe others) is the only thing that causes an unquoted string to be interpreted as two separate command line arguments, but that's not all you have to sorry about when deciding whether or not to quote. You have to worry about all shell metacharacters like ; or | or > or < and `` and many others which have special meaning to the shell unless quoted.
    – Celada
    Nov 13, 2014 at 21:41
  • 4
    @MarcoMarsala xargs takes care of the limited-size argument list problem transparently by breaking it up into multiple invocations of the command.
    – Celada
    Oct 22, 2015 at 19:36
58

Assuming .DS_Store represent files and not directories, the most portable still fast way to do it would be:

sudo find / -name .DS_Store -exec rm {} +

The only risk is for sudo not to be available but it is quite low nowadays.

The -delete option used to demand FreeBSD or later GNU find and is still non standard in a few other find implementations, so is not always available.

The command termination + instead of \; highly optimizes the exec clause by not running the rm command for each and every .DS_Store present on the file system. It is more ubiquitous, being specified by POSIX.

1
  • 11
    -delete is from FreeBSD from 1996, not added to GNU find until 2004, -exec cmd {} + is from SysV in 80s, standardised by POSIX in 1992, added to GNU find in 2005. Feb 9, 2022 at 15:07
33

For a machine such as your macbook you won't find much difference in performance between the two commands. However, if you look at the -exec version you can see a subtle difference:

sudo find / -iname ".file-to-delete"  -exec rm {} \;

This means that you will find all those files with name .file-to-delete. However this search might return some unwanted false positives. When doing something with sudo you should be a bit more careful. The advantage of using -exec rm {} is that you can pass arguments to rm like this:

sudo find / -iname "*~"  -exec rm -i {} \;

In this example I want to remove those backup files that emacs makes. However that tilde could be in some obscure file that I don't know about and could be important. Plus I want to confirm the delete. So I put the option -i on the rm command. This will give me an interactive delete.

Also you can refine the usage of rm to delete directories as well as files:

find /usr/local/share/ -iname "useless" -exec rm -r {} \;

In brief, the -exec gives you a bit more control over the actual command that removes the found item. The advantage is that you use one tool to find the files, another tool to remove them. Also not every version of the find utility has the -delete option. So better to use each tool for its proper job. This is the unix philosophy - one tool, one job, use them together to do what you need to do.

1
  • 11
    See also -ok rm {} \; in place of -exec rm {} \; for interactive confirmation.
    – Kusalananda
    Jun 27, 2018 at 9:44
5

In addition to the existing answers, note that -delete will not delete directories if they are not empty. So you need -exec rm -r in these cases.

For example, this doesn't work:

$ find . -type d -name ".TemporaryItems" -delete
find: cannot delete ‘./.TemporaryItems’: Directory not empty

So you need this instead:

find . -type d -name ".TemporaryItems" -exec rm -rv "{}" +

The example adds the -v (--verbose) option to rm.

You must log in to answer this question.

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