find - exec rm vs -delete

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

    sudo find / -name .DS_Store -delete
    

    and

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

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

  • -delete will perform better because it doesn't have to spawn an external process for each and every matched file.

    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".

    EDIT per comment from @doitmyway: make sure you match on the name and then delete, not the other way around (delete, then match). Otherwise every file will be deleted, whether it matches or not. I.e., DO NOT do this: find / -delete -name .DS_Store.

    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!)

    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.

    On recent `find` you can use `-exec rm {} +` to remove all matched files with single `rm` command.

    `.DS_Store` doesn't contain any special characters at all, so the quotes are unnecessary and change nothing in this case.

    What are other special characters that could possible cause an unquoted string to be interpreted as two separate commands/switches?

    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.

    "but note that there is a portability problem here too: not all versions of find have -print0!" And argument list is not unlimited :-)

    @MarcoMarsala `xargs` takes care of the limited-size argument list problem transparently by breaking it up into multiple invocations of the command.

  • 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 GNU find and is still non standard in many 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.

  • 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.

    See also `-ok rm {} \;` in place of `-exec rm {} \;` for interactive confirmation.

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM