Remove Empty Directories Safely with rmdir
rmdir only removes a directory when it is genuinely empty, making it the safer half of directory cleanup. This guide matches GNU coreutils rmdir 9.4 and takes about ten minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need a shell and write permission on the directory and its parent; none of the examples needs sudo. Check your own version before relying on a detail in a script, because another implementation or release can behave differently.
1. Check the installed command
Confirm the binary and its package version before you build anything on top of it. Both commands are read-only:
$ command -v rmdir
/usr/bin/rmdir
$ rmdir --version
rmdir (GNU coreutils) 9.4
$ dpkg-query -W -f='${Package} ${Version}\n' coreutils
coreutils 9.4-3ubuntu6.1
Your package revision may differ. What matters is that this is the GNU command and that --version reports the implementation you are about to run.
2. Create a disposable directory to test on
Use somewhere under /tmp for a safe smoke test. mkdir -p creates the parent and child in one ordinary, unprivileged step:
$ test_root=$(mktemp -d)
$ mkdir "$test_root/archive"
$ find "$test_root" -maxdepth 2 -type d -print
/tmp/tmp.example
/tmp/tmp.example/archive
Your actual path will not be /tmp/tmp.example. Keep $test_root in the same shell session, and do not replace it with anything broad like / or your home directory.
Checkpoint
Confirm you are about to remove the empty child, not the temporary root itself:
$ find "$test_root/archive" -mindepth 1 -maxdepth 1 -print
$ rmdir "$test_root/archive"
$ test ! -e "$test_root/archive" && echo "archive removed"
archive removed
An empty result from find means no entries below the directory. A successful rmdir normally prints nothing and returns status zero.
3. See the refusal for a non-empty directory
Warning
Rmdir is deliberately conservative, but it still changes the filesystem when it succeeds. Put a file in a second test directory and watch it get refused:
$ mkdir "$test_root/with-file"
$ printf '%s\n' 'keep this file' > "$test_root/with-file/notes.txt"
$ rmdir "$test_root/with-file"
rmdir: failed to remove '/tmp/tmp.example/with-file': Directory not empty
$ printf 'exit status: %s\n' "$?"
exit status: 1
Your path will differ from the one shown, but the file stays exactly where it was, since the failed command removed nothing:
$ test -f "$test_root/with-file/notes.txt" && echo "file still exists"
file still exists
- Do not jump to rm -r just because rmdir refused. Recursive removal is a different, destructive operation entirely.
- Data you care about? Inspect and back it up before doing anything else.
- Disposable test data? Remove the file explicitly after checking the path, then retry:
$ rm -- "$test_root/with-file/notes.txt"
$ rmdir "$test_root/with-file"
$ test ! -e "$test_root/with-file" && echo "directory removed"
directory removed
That rm is irreversible unless you have a backup. rmdir itself has no undo; recovery means restoring the directory from a backup and recreating it.
4. Remove empty ancestors with --parents
Use -p or --parents to remove a directory and then walk up its ancestors, stopping at the first one that is not empty or cannot be removed. Try it on a nested test path:
$ mkdir -p "$test_root/project/cache"
$ mkdir "$test_root/keep"
$ rmdir --parents "$test_root/project/cache"
$ test ! -e "$test_root/project" && echo "empty chain removed"
empty chain removed
rmdir tries the named directory first, then its parent, then the next parent up. The keep marker makes the temporary root non-empty, so it survives and the chain stops there. Never use --parents on a path whose ancestors you actually need to keep. The manual describes rmdir -p a/b as similar to rmdir a/b a, which is a useful mental model, but the explicit option makes intent clearer in a reviewed command.
5. Process several directories and read the diagnostics
rmdir accepts more than one directory at once. Add -v or --verbose to get a line for every directory it processes, which is worth having in a maintenance script:
$ mkdir -p "$test_root/one" "$test_root/two"
$ rmdir --verbose "$test_root/one" "$test_root/two"
rmdir: removing directory, '/tmp/tmp.example/one'
rmdir: removing directory, '/tmp/tmp.example/two'
Wording and the temporary path vary, but each successful operand gets a matching message. Without -v, success is silent, so a script should check $? rather than treat quiet as proof anything actually happened. --ignore-fail-on-non-empty suppresses failures caused specifically by non-empty directories; use it only when that is an expected outcome you will verify separately, since it does not empty a directory or hide permission and missing-path errors.
6. Clean up the test area
Check whether the temporary root still exists, and remove it if it is empty:
$ if [ -d "$test_root" ]; then
> rmdir "$test_root" && echo "temporary root removed"
> fi
temporary root removed
If it reports non-empty, inspect it with find "$test_root" -mindepth 1 -maxdepth 2 -print and remove only what you recognise. Leaving a named temporary directory for later inspection beats running a recursive wildcard against a path you are not sure about.
Done means
- Checked the installed command is GNU coreutils rmdir, and noted its version.
- Verified the target directory before removing it.
- Confirmed plain rmdir refuses non-empty directories and never touches their contents.
- Used --parents only where removing empty ancestors was actually intended.
- Checked exit status or verbose output when processing several paths at once.
- Cleaned up the test area without applying recursive deletion to an uncertain path.