find: "-exec rm {} \;" vs. "-delete" - why is the former widely recommended?
Solution 1:
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.
Solution 2:
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