Because -delete
implies -depth
, or depth-first iteration, so find
first looks at dir1/dir2/dir3/dir4
, notices it's empty, deletes it, then looks at dir1/dir2/dir3
, notices it's (now) empty and deletes it...
The GNU manpage says:
-depth
Process each directory's contents before the directory itself. The -delete
action also implies -depth
.
That's possibly they've considered that it's more commonly useful to be able to delete some files and then possibly the directory containing those files if it was emptied at the same time (-delete
doesn't recursively remove the whole subtree), instead of having to repeat the find
command until all matching files and directories are gone. Or looking at the other way, removing just the leaves of the tree (as we want here) isn't idempotent: running the command again by accident would strip another layer from the directory tree.
In any case, you could have find
run rmdir
instead to keep in the default mode, and add -prune
to prevent it from trying to descend into the now-deleted directory. And let's add -print
for debugging here too, so we see what it removes:
$ mkdir -p dir1/dir2/dir3/dir4
$ find -type d -empty -exec rmdir {} \; -prune -print
./dir1/dir2/dir3/dir4
and this is what remains:
$ find
.
./dir1
./dir1/dir2
./dir1/dir2/dir3
(Here, if the rmdir
fails, the -exec
action evaluates as falsy and the -prune
and -print
actions will not run. So the printout to stdout should only contain what was actually removed. This would be different with -exec rmdir {} +
.)
Of course that assumes you only wanted to delete empty directories here, if you also want to delete empty files, you could do that first with
find -type f -empty -delete
Or build the awful combination that calls rm
for files and rmdir
for directories:
find -empty \( -type f -exec rm {} \; -o -type d -exec rmdir {} \; -prune \) -print
(rm -rf
would also obviously work, but is riskier.)