17

rmdir deletes only an empty directory. To delete recursively, rm -rf is used.

  • Why doesn't rmdir have a recursive option? Logically, when I am deleting a directory, I want to use rmdir.
  • Given that rm is used for deleting a directory in all but the simplest case, why does rmdir even exist? The functionality is subsumed in rm.

Is this just a historical accident?

Joshua Fox
  • 611
  • 6
  • 12
  • 9
    See [here](https://unix.stackexchange.com/questions/374804): `rmdir` is safer when one wants to ensure to only operate on empty directories. Recursive operation does not make sense with this in mind. Note that `-p` for `a/b/c` is however somewhat an analogue to recursive operations. – FelixJN Dec 19 '21 at 11:42
  • 1
    The Unix developers fixed this in Plan 9. Its rm removes directories, too. https://9p.io/magic/man2html/1/rm – Mark Plotnick Dec 19 '21 at 11:43
  • 2
    ... as does `rm -d` (at least in the GNU implementation). – Stephen Kitt Dec 19 '21 at 11:46
  • @FelixJN Indeed, rmdir only works on empty directories. But certain safety measures are also implemented, or implementable, for rm. It seems that the answer to my question is that it is just a historical accident – Joshua Fox Dec 19 '21 at 11:51
  • 1
    Logically when you're recursively deleting something you're deleting **files** a well. The command name is "remove directory". – Artem S. Tashkinov Dec 19 '21 at 11:54
  • @ArtemS.Tashkinov Yet `rm -r` on directory `x` that has in it empty directory `y` works as expected. – Joshua Fox Dec 19 '21 at 11:57
  • 1
    @JoshuaFox And I see zero contradiction because from `man rm`: **rm - remove files or directories** – Artem S. Tashkinov Dec 19 '21 at 11:59
  • @ArtemS.Tashkinov I agree. Indeed, that is at the heart of the point I am making in the OP – Joshua Fox Dec 19 '21 at 11:59
  • 12
    _"The functionality is subsumed in rm."_ - Not entirely; `rmdir` removes only empty directories. `rm -r` will also delete full directories, and `rm -d` happily removes files along with empty directories. That may sound pedantic, but I actually rely on that behaviour quite a bit; when I've manipulated a bunch of files using temporary directories, a simple `rmdir *` will remove all empty directories, but leave everything else. It may not be by design, but it is useful to me :) – marcelm Dec 19 '21 at 21:07
  • 1
    `rmdir very_important_dir` => `rmdir: failed to remove 'very_important_dir': Directory not empty` That's an excellent feature IMHO. – Eric Duminil Dec 19 '21 at 22:10
  • 2
    @marcelm you can get the same effect with `rm -d */` ;-). (But `rm -d` isn’t standard.) – Stephen Kitt Dec 20 '21 at 06:48
  • 2
    @StephenKitt Fair enough! More dangerous if you mistype and forget the `/` though ;) – marcelm Dec 20 '21 at 13:17
  • @marcelm indeed! One might say it’s in keeping with Unix tradition of enabling users to shoot their own feet off at the slightest mistake... – Stephen Kitt Dec 20 '21 at 13:29

2 Answers2

35

Unlinking directories was originally a privileged operation:

It is also illegal to unlink a directory (except for the super-user).

So rmdir was implemented as a small binary which only removed directories, which at the time involved removing .. and . inside the directory, and then the directory itself. rmdir was designed to be setuid root; it performs separate permission tests using access to determine whether the real user is allowed to remove a directory. Like any setuid root binary, it’s better to keep it simple and tightly-focused.

rm -r actually used this separate binary to delete directories as necessary.

It seems the lasting difference between rm -r and rmdir is the result of this initial difference.

Presumably since rm acquired the ability to delete recursively early on, and rmdir was supposed to have a very small remit, it was never deemed useful to give rmdir the ability to delete recursively itself.

Stephen Kitt
  • 411,918
  • 54
  • 1,065
  • 1,164
  • 4
    Also, if your script is about to remove a directory, `rm -rf` would not complain if the directory was not empty, while `rmdir` would. This may matter for the user. – Kusalananda Dec 19 '21 at 14:03
  • 1
    I was amused by "removing .. and . inside the directory" because I had a trainee who somehow created a file named "." inside the user directory on the webserver. It wasn't so easy to remove. – Wastrel Dec 20 '21 at 15:55
-3

An alternative to recursive rmdir (which would be handy) would be something like this:

find . -depth -type d -exec rmdir {} \;

This will remove empty directories only, and give lots of harmless errors if some of them are not empty.

A recursive rmdir might be smarter and abort a subtree when it got an error, rather than continue to get cascading errors, but likely would not be faster.

As pointed out, rmdir does have the -p option, which isn't exactly recursive. And the ability to use find as above likely removed motivation to add a recursive option for it, as the advantages would be small.

user10489
  • 5,834
  • 1
  • 10
  • 22
  • 4
    Some `find` implementations have an `-empty` predicate: `find . -depth -type d -empty -exec rmdir {} +` – Kusalananda Dec 19 '21 at 14:41
  • 1
    That would suppress the harmless errors, not sure if it would have any benefit beyond that. – user10489 Dec 19 '21 at 14:58
  • 2
    Well, your main concern in your answer seemed to be getting errors due to non-empty directories, so I suggested a fix for it. That's all. – Kusalananda Dec 19 '21 at 15:00
  • 1
    Not criticizing -- it's a good point. Just wondering if the extra typing is worth the fewer errors. – user10489 Dec 19 '21 at 15:06
  • 1
    With a nice shell and GNU coreutils, you can do stuff like `rmdir -p **/*/` to attempt removal of every directory under the current one. `-p` removes "parent" directories, e.g. `rmdir -p foo/bar` (tries to) remove `foo` as well, succeeding if it's empty after removing `bar`. (And yes, there might be command line length limits; I'm not suggesting this for scripted usage, just interactive.) – Peter Cordes Dec 19 '21 at 20:41
  • @PeterCordes you don’t even need the GNU version of `rmdir` for that, `rmdir -p` is [part of POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/rmdir.html). – Stephen Kitt Dec 19 '21 at 22:27
  • 4
    This does not attempt to answer the question. – Carsten S Dec 20 '21 at 11:14
  • @CarstenS : yes it does. It shows that rmdir can be recursive with a little help. – user10489 Dec 20 '21 at 12:20
  • 6
    This doesn't answer the question that was asked. You can't meaningfully answer "_why not?_" with "_Here's an alternative_". – Toby Speight Dec 20 '21 at 14:40
  • @user10489, well, it's _`find`_ that's recursive there, `rmdir` still just non-recursively removes the files given to it by `find`. With at least GNU find, I think you could also just do `find . -type d -empty -delete`. (or without the `-empty` if you want the errors for non-empty dirs) – ilkkachu Dec 21 '21 at 12:19
  • Does the OP find this alternative useful? – user10489 Dec 21 '21 at 12:57