6

Why is it that that articles on find always use -exec rm {} \; in cases where the shorter and easier to type and read -delete seems, as far as I can tell, to work just as well?

I realize there are cases where rm with some options like -r -f for example might do some more tricks, but there are tons of examples of plain -exec rm {} \; in tutorials all over the net but virtually no examples of the use of -delete.

What am I missing? Is there some reason for this?

11

tl;dr: -delete is not required by POSIX, -exec is.


Facts

POSIX 1003.1 man page for find specifies -exec but not -delete.

This means -exec should work virtually everywhere. I would be surprised finding find that has -delete without -exec. The opposite is quite possible. Especially lightweight systems that use busybox tend to provide basic command line options only.

E.g. I have an OpenWRT on one of my routers and its find understands -exec, it doesn't understand -delete.

Not having -delete is not a big deal when you have -exec rm …. On the other hand -delete cannot replace -exec in general. It's a wise design to allow omitting -delete first.


Personal experience, observations and opinions

The above should be the primary reason why -exec rm {} \; is so widely recommended. The secondary may be a snowball effect. Users read articles and examples, get familiar with -exec and publish their own commands (e.g. here on Super User). Some of them may not even know -delete exists.

Few times I have seen (or given) remarks like 'You can use -delete instead'. And the responses were like 'Thanks, I didn't know that'. I don't remember any response 'I know, but this is not POSIX'.


Having said all this I tend to mention -delete whenever -exec rm {} \; appears. The reason is -delete doesn't spawn a new process, while -exec rm {} \; invokes a separate rm for each matched file. If you cannot use -delete then your next thought should be -exec rm {} + that can remove multiple files with a single rm (still it will invoke rm more than once if needed).

Why isn't -exec … + widely recommended then? It might be because of its limitations. I can imagine an inexperienced user thinking 'This works with rm, let me use it with mv!' Then -exec mv {} foo/ + doesn't work because {} needs to be at the end, just before +. The user gets frustrated and runs back to mama Windows.


Recommending -delete is usually safe here on Super User, I think. Most questions specify "big" OS-es, find commands there are rich with options. And even if there's a user whose find is limited I will probably get feedback. He or she says the solution doesn't work for them and I suggest -exec rm … instead, explain the issue etc.

A standalone article that recommends -delete won't get such feedback. In case of any trouble a user will simply go to the next link returned by Google.

  • That is a well written exposition. Clear, concise, and practical. Thanks for taking the trouble. – Lew Rockwell Fan Jun 25 '17 at 3:19
3

The difference is in flexibility. If you use -exec then you execute a command for each selected file. If you use -exec then you have flexibility to apply other find options. With -delete you are restricted in use of -prune. Moreover, your placement of -delete impacts your results. See documentation snippet below:

-delete
    Delete  files;  true  if removal succeeded.  If the removal failed, 
    an error message is issued.  If -delete fails, find’s exit status will be
        nonzero (when it eventually exits).  Use of -delete automatically turns on 
    the ‘-depth’ option.

    Warnings: Don’t forget that the find command line is evaluated as an 
    expression, so putting -delete first will make find try to delete every-
    thing  below  the  starting  points  you  specified.   When testing a find 
    command line that you later intend to use with -delete, you should
    explicitly specify -depth in order to avoid later surprises.  
    Because -delete implies -depth, you cannot  usefully  use  -prune  and  -delete
    together.

-exec command ;
    Execute  command;  true  if 0 status is returned.  All following arguments 
    to find are taken to be arguments to the command until an argument
    consisting of ‘;’ is encountered.  The string ‘{}’ is replaced by the 
    current file name being processed everywhere it occurs in the arguments
    to  the  command, not just in arguments where it is alone, as in 
    some versions of find.  Both of these constructions might need to be escaped
    (with a ‘\’) or quoted to protect them from expansion by the shell.  
    See the EXAMPLES section for examples of the use of  the  -exec  option.
    The specified command is run once for each matched file.  The 
    command is executed in the starting directory.   There are unavoidable security
    problems surrounding use of the -exec action; you should use the -execdir 
    option instead.

-exec command {} +
    This variant of the -exec action runs the specified command on the 
    selected files, but the command line is built by appending  each  selected
    file name at the end; the total number of invocations of the command 
    will be much less than the number of matched files.  The command line is
    built in much the same way that xargs builds its command lines.  
    Only one instance of ‘{}’ is allowed within the  command.   The  command  is
    executed in the starting directory
  • Flexibility is certainly a sound point. If I use exec every time I could have used delete, maybe I can eventually remember where all the those characters that look like Popeye cussing go, without having to look it up each time I NEED exec. – Lew Rockwell Fan Jun 25 '17 at 3:23
0

The older "widely recommended" form, still preferred on systems without -delete, is (replacing the ellipses as appropriate):

find ... -print0 ... | xargs -0 /bin/rm ...

This limits processes to two instead of letting -exec spawn potentially thousands, while still handling filenames with special characters correctly (whereas using -print0 and omitting -0 from xargs would allow filenames to be split erroneously).

It uses one more process than find with-delete and has some interprocess communication overhead, but is, as with -delete vastly faster than find ... -exec /bin/rm '{}' \' in nearly all cases.

  • The explicit question is "why is -exec rm {} \; widely recommended?" Your code is sane, your explanation is right; but it's just a digression, a comment about yet another way to do the same thing. The question doesn't mention xargs nor it asks for alternatives to -delete. This is the second time I claim one of your answers doesn't answer the question. You have just improved your other answer and convinced me it does answer the question. Please convince me here as well. – Kamil Maciorowski Jun 14 '18 at 5:04
  • The -exec rm is not recommendable on many systems, for reasons I gave - lack of support, or a desire to restrict process count. "widely recommended" does not mean ideal for all circumstances, and failing to address that assumption seems irresponsible. The other answers already gave useful detail for the exact question, simply rephrasing the coherent material adds nothing. What I've given is complementary but relevant. I'm not here to supercede the answer contributions, and perfectly fine if someone else incorporates it into a standalone answer. Feel free to do so yourself. – Alex North-Keys Jun 15 '18 at 6:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.