rmdir refuses non-empty directories on purpose — it is a deliberately narrow tool that cannot cause a recursive delete by accident. To remove a directory with contents, use rm -r directory. Add -f only when you want errors suppressed, and understand that the two flags do very different things.
The error is clear enough:
Table of contents
- The two commands and what separates them
- Look before you delete
- When rm -rf fails anyway
- Where rmdir is the better choice
- How this fits the rest of the stack
- FAQ
The two commands and what separates them
$ rmdir myfolder
rmdir: failed to remove 'myfolder': Directory not empty
rmdir calls the rmdir(2) system call, which the kernel refuses on a non-empty directory. That is not a limitation somebody forgot to fix — it is the safety property that makes rmdir useful in scripts, where you want to remove a directory only if nothing is in it.
rm -r walks the tree and unlinks everything it finds. Different tool, different guarantees.
rm -r myfolder # remove the directory and everything under it
rm -ri myfolder # ask before each file
rm -rf myfolder # remove, suppressing errors and prompts
The distinction between -r and -f gets blurred because people type them together as one word. They are unrelated:
-ris recursion. Without it,rmwill not descend into directories at all.-fsuppresses prompts and error messages, and makesrmexit 0 even if the target did not exist.
rm -r on its own already removes a full tree. The -f adds nothing to the deletion — it only removes the feedback that might have stopped you.
Look before you delete
The habit that prevents most rm -rf accidents costs one command:
ls -la myfolder
du -sh myfolder
find myfolder -type f | wc -l
If you expected a scratch directory and du reports 40GB across 200,000 files, that is a useful moment to have before the deletion rather than after.
find also gives you a genuine dry run, which rm does not have:
find myfolder -type f -name "*.log" -print # list matches
find myfolder -type f -name "*.log" -delete # then delete them
Run the -print form, read the output, then re-run with -delete. For anything selective this is strictly better than rm -rf, because you see the exact set before it goes.
Two habits worth adopting permanently:
- Never end an
rm -rfargument with a variable that could be empty.rm -rf "$DIR/"withDIRunset expands torm -rf /. Guard it:[ -n "$DIR" ] && rm -rf "$DIR". - Use relative paths from a known directory rather than absolute paths typed from memory.
When rm -rf fails anyway
-f suppresses complaints, so a silent failure is easy to miss. The usual causes:
Permissions. To remove a file you need write and execute on its parent directory, not on the file. A file you own inside a directory you cannot write is not yours to delete.
ls -ld myfolder # check the directory's permissions
sudo rm -r myfolder # if the directory belongs to another user
A mount point. You cannot remove a directory that has a filesystem mounted on it. Check with mount | grep myfolder, unmount, then remove.
Files in use. Deleting an open file works on Linux — the name goes, the inode survives until the last handle closes. So the space is not reclaimed even though the file is gone. lsof +D myfolder shows what is holding it.
Immutable attributes. Rare but genuinely confusing when hit, because root cannot delete the file either:
lsattr myfolder/stubborn-file # look for 'i'
sudo chattr -i myfolder/stubborn-file
Argument list too long. With hundreds of thousands of files, glob expansion overflows. Use find instead, which does not build one enormous argument list:
find myfolder -type f -delete && rmdir myfolder
Where rmdir is the better choice
Because it fails on non-empty directories, rmdir is the correct tool whenever emptiness is the condition you actually care about.
rmdir /tmp/build-workspace 2>/dev/null || echo "not empty, leaving it alone"
That is a script that cleans up after itself and refuses to delete anything unexpected. The equivalent with rm -rf would remove whatever happened to be there, including output somebody else was relying on.
-p removes a chain of empty parents in one go, which is tidy for nested scratch paths:
rmdir -p a/b/c # removes c, then b, then a, stopping at the first non-empty one
And to sweep every empty directory out of a tree without touching anything containing files:
find . -type d -empty -delete
That is a genuinely safe cleanup, because the -empty test guarantees nothing with contents is removed.
How this fits the rest of the stack
The reason rmdir exists alongside rm -r is that a narrow tool which refuses ambiguous input is worth more than a general one that always succeeds. You want the command to fail when the situation is not what you assumed.
That principle scales up. A deploy that fails loudly on a bad build is better than one that ships something unexpected, and infrastructure you can roll back is better than infrastructure you have to repair by hand. RunxBuild keeps a build log and a rollback target for every deploy, so a bad release is a selection rather than a recovery operation. If you want to see what a service, its database and its storage come to before committing, the RunxBuild hosting calculator breaks it out line by line.
Useful related references:
- Remove Directory Linux: rmdir for Empty, rm -rf for Recursive
- Delete Directory Linux: rmdir, rm -rf, and find -delete
- Linux Remove Directory: rm, rmdir, and Not Deleting Your Server
- Services on RunxBuild
FAQ
Why does rmdir say directory not empty?
Because that is its entire design. rmdir calls a system call that the kernel refuses on non-empty directories, which makes it safe to use in scripts where you only want to remove a directory if nothing is in it. Use rm -r when you intend to delete contents.
What is the difference between rm -r and rm -rf?
-r is what makes rm descend into directories, and on its own it already removes an entire tree. -f only suppresses prompts and error messages and forces a zero exit code. Adding -f does not delete more — it removes the feedback that might have warned you.
How do I delete a directory with too many files for rm?
When glob expansion overflows the argument limit, use find myfolder -type f -delete followed by rmdir myfolder. find processes entries incrementally instead of building one enormous argument list.
Why can I not delete a file even as root?
Check for the immutable attribute with lsattr — a file flagged i cannot be deleted by anyone until you clear it with chattr -i. The other common cause is a mount point, which cannot be removed until the filesystem is unmounted.
How do I safely remove only empty directories in a tree?
find . -type d -empty -delete removes every empty directory and cannot touch anything containing files, because the -empty test does the filtering. For a known nested path, rmdir -p a/b/c removes empty parents and stops at the first non-empty one.