🗑️ rmdir Command

Safe Directory Removal in Linux

About the rmdir Command

The rmdir (remove directory) command is used to delete empty directories in Linux and Unix systems. Unlike rm -r which can recursively delete directories with all their contents, rmdir only removes empty directories, making it a safer choice when you want to ensure you're not accidentally deleting files. If a directory contains any files or subdirectories, rmdir will refuse to delete it and display an error message.

Key safety feature: The rmdir command's refusal to delete non-empty directories is a protective measure that prevents accidental data loss. This makes it the preferred command for cleaning up empty directory structures, especially in scripts where you want to remove only truly empty directories without risking file deletion.

Common use cases: Cleaning up empty build directories, removing old empty cache folders, tidying up directory structures after moving files, and safely removing temporary directory hierarchies that should be empty.

Basic Syntax: rmdir [OPTIONS] DIRECTORY... Common Usage: rmdir empty_dir # Remove single empty directory rmdir dir1 dir2 dir3 # Remove multiple empty directories rmdir -p path/to/empty/dir # Remove directory and empty parent directories rmdir -v directory # Verbose output (explain what's being done) rmdir --ignore-fail-on-non-empty dir # Don't error on non-empty dirs Common Options: -p, --parents Remove directory and its ancestors (if empty) -v, --verbose Explain what is being done --ignore-fail-on-non-empty Ignore failures due to non-empty directories

Detailed Examples

1Basic Directory Removal

Remove a single empty directory.

$ ls -la total 12 drwxr-xr-x 3 user user 4096 Nov 28 10:00 . drwxr-xr-x 5 user user 4096 Nov 28 09:55 .. drwxr-xr-x 2 user user 4096 Nov 28 10:00 empty_folder $ rmdir empty_folder $ ls -la total 8 drwxr-xr-x 2 user user 4096 Nov 28 10:01 . drwxr-xr-x 5 user user 4096 Nov 28 09:55 ..
What's happening: The rmdir empty_folder command successfully removes the empty directory. Notice that the directory must be completely empty - no files, no hidden files, no subdirectories. The command completes silently with no output when successful (typical Unix behavior). After removal, the directory no longer appears in the listing. Important behavior: If the directory contains any files (including hidden files like .gitignore), rmdir will fail with an error message "rmdir: failed to remove 'directory': Directory not empty". This safety feature prevents accidental deletion of files.
Use ls -la directory before rmdir to verify the directory is truly empty. The -a flag shows hidden files that might prevent removal.

2Attempting to Remove Non-Empty Directory

Understanding what happens when you try to remove a directory that contains files.

$ ls -la test_dir/ total 12 drwxr-xr-x 2 user user 4096 Nov 28 10:05 . drwxr-xr-x 3 user user 4096 Nov 28 10:05 .. -rw-r--r-- 1 user user 45 Nov 28 10:05 file.txt $ rmdir test_dir rmdir: failed to remove 'test_dir': Directory not empty $ echo $? 1
What's happening: When rmdir encounters a non-empty directory, it refuses to remove it and displays an error message. The directory contains file.txt, so rmdir fails. The command returns exit status 1 (failure) which can be checked with $?. This protective behavior is rmdir's main feature - it will never delete files. If you see this error: You have three options: (1) Manually delete or move the files first, then use rmdir. (2) Use rm -r directory to recursively delete everything (dangerous!). (3) Use rmdir --ignore-fail-on-non-empty directory to suppress the error but leave the directory intact. Option 1 is safest when you want to ensure no important files are accidentally deleted.
The exit status of 1 indicates failure. In scripts, always check the exit status of rmdir if you need to know whether the removal succeeded. Use if rmdir directory; then ... else ... fi for conditional execution.

3Remove Multiple Empty Directories

Delete several empty directories in a single command.

$ ls -d */ cache/ logs/ temp/ old_backups/ $ rmdir cache logs temp old_backups $ ls -d */ 2>/dev/null # No output - all directories removed
What's happening: Rmdir can accept multiple directory names as arguments and will attempt to remove each one. If all four directories are empty, they'll all be removed in one operation. Mixed scenarios: If some directories are empty and others aren't, rmdir will remove the empty ones and display error messages for the non-empty ones. For example, if logs contains files, rmdir would remove cache, temp, and old_backups successfully but fail on logs with an error message. This partial success is useful - you don't need all directories to be empty for the command to be worthwhile. The command processes each directory independently.
Use shell globbing carefully: rmdir */ attempts to remove all subdirectories in the current directory. Only empty ones will be removed, but verify what you're targeting before running it.

4Verbose Mode

Using -v flag to see confirmation of what's being removed.

$ ls -d */ build/ dist/ temp/ $ rmdir -v build dist temp rmdir: removing directory, 'build' rmdir: removing directory, 'dist' rmdir: removing directory, 'temp' $ ls -d */ 2>/dev/null # No output - all removed
What's happening: The -v (verbose) flag makes rmdir report each directory as it's removed. This provides confirmation that operations are happening as expected, which is particularly useful in scripts or when removing many directories. The verbose output goes to standard output, so it can be captured in logs. Why use verbose: (1) Confirmation - you see exactly what was removed. (2) Debugging - if a script fails, you can see how far it got. (3) Logging - capture what was cleaned up for audit trails. (4) Learning - understanding the command's behavior by seeing its actions. In production scripts, verbose output is valuable for troubleshooting and maintaining audit logs of filesystem changes.
Combine with redirection for logging: rmdir -v old_dirs/* 2>&1 | tee cleanup.log captures both successful removals and error messages to a log file.

5Remove Parent Directories (-p flag)

Recursively remove a directory and its empty parent directories.

$ mkdir -p projects/2023/old/archived/empty $ tree projects projects └── 2023 └── old └── archived └── empty $ rmdir -p projects/2023/old/archived/empty $ tree projects tree: projects: No such file or directory $ ls projects 2>/dev/null ls: cannot access 'projects': No such file or directory
What's happening: The -p (parents) flag removes not only the specified directory but also its parent directories if they become empty after the removal. In this example, empty is removed first, which leaves archived empty, so it's removed. Then old becomes empty and is removed, then 2023, and finally projects. The entire directory hierarchy is cleaned up in one command. Important condition: The -p flag only removes parent directories that become empty as a result of the removal. If any parent directory contains other files or directories, rmdir stops at that level. For example, if 2023 contained another directory called current, rmdir would remove empty, archived, and old, but stop at 2023 because it's not empty. This is the inverse of mkdir -p which creates parent directories.
The -p flag is extremely useful for cleaning up deep directory structures that should be completely gone. It's safer than rm -r because it will only remove empty directories, never files.
Be careful with the path you specify. rmdir -p /home/user/projects/test could theoretically remove /home/user/projects, /home/user, and even /home if they all became empty (which is unlikely but possible in edge cases). Always use relative paths or verify the hierarchy.

6Ignore Failures on Non-Empty Directories

Suppress errors when encountering non-empty directories.

$ ls -la cleanup/ total 20 drwxr-xr-x 5 user user 4096 Nov 28 11:00 . drwxr-xr-x 3 user user 4096 Nov 28 11:00 .. drwxr-xr-x 2 user user 4096 Nov 28 11:00 empty1 drwxr-xr-x 2 user user 4096 Nov 28 11:00 empty2 drwxr-xr-x 2 user user 4096 Nov 28 11:00 has_files -rw-r--r-- 1 user user 10 Nov 28 11:00 has_files/data.txt $ rmdir --ignore-fail-on-non-empty cleanup/* $ ls cleanup/ has_files $ ls cleanup/has_files/ data.txt
What's happening: The --ignore-fail-on-non-empty flag tells rmdir to silently skip directories that contain files rather than reporting an error. In this example, empty1 and empty2 are successfully removed, while has_files is left intact because it contains data.txt. No error message is displayed for has_files. Use case: This is valuable in cleanup scripts where you want to remove all empty directories but don't care about (or want to preserve) non-empty ones. For example, cleaning up a build directory structure where some output directories are empty (can be removed) and others contain build artifacts (should be kept). The command succeeds (exit status 0) even if some directories couldn't be removed. This is different from standard behavior where encountering a non-empty directory causes rmdir to return exit status 1.
This flag is particularly useful in cron jobs or automated cleanup scripts where you don't want the script to fail just because some directories aren't empty yet.

7Using rmdir in Scripts for Safe Cleanup

Practical script example for cleaning up empty directories.

#!/bin/bash # cleanup_empty_dirs.sh - Remove empty directories from a project PROJECT_DIR="/home/user/project" LOG_FILE="/var/log/cleanup.log" echo "$(date): Starting cleanup of empty directories" >> "$LOG_FILE" # Find and remove all empty directories find "$PROJECT_DIR" -type d -empty -print0 | while IFS= read -r -d '' dir; do if rmdir -v "$dir" 2>&1; then echo "$(date): Removed: $dir" >> "$LOG_FILE" else echo "$(date): Failed to remove: $dir" >> "$LOG_FILE" fi done echo "$(date): Cleanup complete" >> "$LOG_FILE"
$ ./cleanup_empty_dirs.sh # Check log file $ tail /var/log/cleanup.log Wed Nov 28 11:30:00 EST 2025: Starting cleanup of empty directories rmdir: removing directory, '/home/user/project/temp' Wed Nov 28 11:30:00 EST 2025: Removed: /home/user/project/temp rmdir: removing directory, '/home/user/project/cache' Wed Nov 28 11:30:00 EST 2025: Removed: /home/user/project/cache Wed Nov 28 11:30:00 EST 2025: Cleanup complete
What's happening: This script demonstrates safe, logged directory cleanup. The find command locates all empty directories (-type d -empty), then the while loop processes each one. Using -print0 and read -r -d '' handles directory names with spaces or special characters safely. Each removal is logged with a timestamp. The script captures both successful removals and failures. Key safety features: (1) Only targets empty directories (find's -empty flag). (2) Uses rmdir which won't delete files. (3) Logs all actions for audit trail. (4) Handles edge cases like spaces in directory names. (5) Doesn't fail completely if one removal fails. This pattern is production-ready and demonstrates best practices for automated filesystem maintenance.
Enhance this script with: dry-run mode (echo instead of rmdir), age-based filtering (find -mtime +30), specific directory exclusions (find -path ./keep -prune), or email notifications on completion.

8Combining with find for Bulk Operations

Advanced usage: finding and removing all empty directories in a tree.

$ tree project/ project/ ├── build │ ├── debug │ └── release ├── docs │ └── api ├── src │ ├── main.c │ └── utils └── tests └── unit $ find project/ -type d -empty -delete # Alternative safer approach: $ find project/ -type d -empty -exec rmdir -v {} \; rmdir: removing directory, 'project/build/debug' rmdir: removing directory, 'project/build/release' rmdir: removing directory, 'project/docs/api' rmdir: removing directory, 'project/src/utils' rmdir: removing directory, 'project/tests/unit' $ tree project/ project/ ├── build ├── docs ├── src │ └── main.c └── tests
What's happening: The find command with -type d -empty locates all empty directories recursively. Two approaches are shown: (1) -delete flag removes them directly (fast but no feedback). (2) -exec rmdir -v {} \; uses rmdir on each one (verbose output for confirmation). The second approach is safer because rmdir will refuse if the directory somehow became non-empty between find identifying it and rmdir attempting removal. Important note: The find command processes directories depth-first when using -delete, which matters because removing a subdirectory might make its parent directory empty. The -exec approach with rmdir handles this naturally. Parent directories like build, docs, and tests remain because they still contain something (in this case, subdirectories or files).
Using find with -delete is powerful but potentially dangerous. Always test with -print first to see what would be deleted: find project/ -type d -empty -print. Once verified, replace -print with -delete.
To remove empty directories multiple times until no more exist (handling nested empty dirs): while find project/ -type d -empty -delete -print | grep -q .; do :; done

9Checking Before Removal

Defensive programming: verify directory is empty before removal.

#!/bin/bash # safe_rmdir.sh - Remove directory only if truly empty dir="$1" if [ -z "$dir" ]; then echo "Usage: $0 <directory>" exit 1 fi if [ ! -d "$dir" ]; then echo "Error: $dir is not a directory" exit 1 fi # Check if directory is empty (including hidden files) if [ -z "$(ls -A "$dir")" ]; then echo "Directory is empty. Removing..." if rmdir "$dir"; then echo "Successfully removed $dir" else echo "Failed to remove $dir" exit 1 fi else echo "Directory is not empty. Contents:" ls -la "$dir" exit 1 fi
$ ./safe_rmdir.sh test_empty Directory is empty. Removing... Successfully removed test_empty $ ./safe_rmdir.sh test_has_files Directory is not empty. Contents: total 12 drwxr-xr-x 2 user user 4096 Nov 28 12:00 . drwxr-xr-x 5 user user 4096 Nov 28 12:00 .. -rw-r--r-- 1 user user 10 Nov 28 12:00 .hidden -rw-r--r-- 1 user user 20 Nov 28 12:00 visible.txt
What's happening: This script demonstrates defensive directory removal with multiple checks: (1) Validates an argument was provided. (2) Verifies the target exists and is a directory. (3) Uses ls -A to check for contents (including hidden files - the -A flag shows all except . and ..). (4) Only attempts removal if truly empty. (5) Reports success or failure clearly. The ls -A trick: ls -A directory returns empty output if the directory is empty, non-empty output if it contains anything. The test [ -z "$(ls -A "$dir")" ] checks if the output is empty (zero-length string). This catches hidden files that a simple ls would miss. This pattern is excellent for interactive scripts where you want to be absolutely certain before removing directories, or when you want to provide detailed feedback about why removal failed.
For even more safety, add a confirmation prompt before removal: read -p "Really remove $dir? (y/n) " confirm; [[ $confirm == [Yy] ]] || exit 0

10Cleaning Up Directory Trees Bottom-Up

Advanced technique: removing nested empty directories from deepest to shallowest.

$ mkdir -p deep/level1/level2/level3/level4 $ tree deep/ deep/ └── level1 └── level2 └── level3 └── level4 # Remove from deepest first $ find deep/ -depth -type d -empty -exec rmdir -v {} \; rmdir: removing directory, 'deep/level1/level2/level3/level4' rmdir: removing directory, 'deep/level1/level2/level3' rmdir: removing directory, 'deep/level1/level2' rmdir: removing directory, 'deep/level1' rmdir: removing directory, 'deep' $ ls deep/ 2>/dev/null ls: cannot access 'deep/': No such file or directory # Alternative using rmdir -p $ mkdir -p deep/level1/level2/level3/level4 $ rmdir -pv deep/level1/level2/level3/level4 rmdir: removing directory, 'deep/level1/level2/level3/level4' rmdir: removing directory, 'deep/level1/level2/level3' rmdir: removing directory, 'deep/level1/level2' rmdir: removing directory, 'deep/level1' rmdir: removing directory, 'deep'
What's happening: Two approaches to remove nested empty directories: Approach 1: find -depth processes directories depth-first, meaning deepest directories are encountered first. This ensures child directories are removed before their parents, allowing the parents to become empty and be removed in turn. The -depth flag is crucial - without it, find might try to remove a parent before its children, causing failures. Approach 2: rmdir -p does this automatically, climbing up the directory tree and removing empty ancestors. Both achieve the same result but -p is simpler when you know the full path. The find approach is more flexible for finding and removing all empty directory chains in a tree structure. Real-world use: This is perfect for cleaning up directory structures created by build systems, temporary file hierarchies, or scaffolding that's no longer needed.
The find -depth approach is more powerful because it can handle multiple directory trees: find . -depth -type d -empty -delete removes all empty directories everywhere in the current tree, including complex nested structures.

Command Options Reference

Option Long Form Description
-p --parents Remove directory and its ancestors (empty parent directories)
-v --verbose Output a diagnostic message for every directory processed
--ignore-fail-on-non-empty Ignore failures that are due to directories not being empty
--help Display help message and exit
--version Output version information and exit

rmdir vs. rm -r: Critical Differences

Understanding the Key Differences

Feature rmdir rm -r
Can delete files ❌ No - only empty directories ✅ Yes - deletes everything
Removes non-empty dirs ❌ No - refuses with error ✅ Yes - recursive deletion
Safety level 🟢 Very safe - won't delete files 🔴 Dangerous - can delete everything
Requires confirmation No - safe by design No (unless using -i flag)
Use when You want to remove ONLY empty directories You need to remove directory with contents
Error on non-empty Yes - this is a feature No - deletes everything silently
Hidden files matter Yes - .hidden files prevent removal No - deletes hidden files too
The command rm -rf is one of the most dangerous commands in Linux. It recursively deletes everything without confirmation. NEVER run rm -rf without being absolutely certain of the path. A typo can destroy your entire system. Always use rmdir when you only want to remove empty directories.

When to Use Which Command

  • Use rmdir when:
    • You want to remove only empty directories
    • You want to be safe and avoid accidental file deletion
    • You're cleaning up directory structures that should be empty
    • You want an error if the directory isn't empty (indicating something unexpected)
    • Writing scripts where safety is paramount
  • Use rm -r when:
    • You explicitly want to delete a directory and all its contents
    • You've verified what you're deleting (use ls -R first)
    • You're removing temporary or build directories that should go away
    • Consider using rm -ri for interactive confirmation on each file

Best Practices and Safety

Safe Directory Removal Guidelines

  • Always verify before removing: Use ls -la directory to check contents before rmdir
  • Check for hidden files: Hidden files (starting with .) prevent removal - use ls -A to see them
  • Use absolute paths in scripts: Avoid confusion about which directory you're removing
  • Test with echo first: In scripts, test with echo rmdir $dir before actually running rmdir
  • Log removals: Keep audit trails of what was removed and when, especially in production
  • Use -v in scripts: Verbose output helps with debugging and logging
  • Prefer rmdir over rm -r: When possible, use rmdir's safety features
  • Handle failures gracefully: Check exit status and don't assume rmdir succeeded
  • Be careful with wildcards: rmdir * tries to remove all subdirectories - verify first
  • Document expectations: If a directory should be empty, document why in your scripts

Common Patterns and Idioms

  • Safe removal with verification: [ -z "$(ls -A dir)" ] && rmdir dir || echo "Directory not empty"
  • Remove if empty, create if missing: rmdir dir 2>/dev/null; mkdir -p dir
  • Remove all empty subdirectories: find . -type d -empty -delete
  • Conditional removal in scripts: if rmdir "$dir" 2>/dev/null; then echo "Removed"; fi
  • Remove with logging: rmdir -v dir 2>&1 | tee -a removal.log

Common Use Cases

Cleanup After File Migration

#!/bin/bash # After moving files, remove empty source directories SOURCE="/old/location" find "$SOURCE" -type d -empty -delete echo "Cleanup complete - removed all empty directories"

Build System Cleanup

#!/bin/bash # Remove empty build artifact directories for dir in build/*/; do if [ -z "$(ls -A "$dir")" ]; then rmdir -v "$dir" fi done

Temporary Directory Cleanup

#!/bin/bash # Clean up old temporary directories (empty only) find /tmp/myapp-* -type d -mtime +7 -empty -exec rmdir -v {} \;

Project Structure Cleanup

#!/bin/bash # Remove all empty __pycache__ and .pytest_cache directories find . -type d \( -name "__pycache__" -o -name ".pytest_cache" \) -empty -delete

Troubleshooting Common Issues

Issue: "Directory not empty" but ls shows nothing
Cause: Hidden files exist. Solution: Use ls -a directory to see all files including those starting with dot (.). Hidden files like .gitkeep, .DS_Store, or .hidden prevent removal.
Issue: rmdir removes wrong directory
Cause: Relative path confusion or wrong current directory. Solution: Always use absolute paths in scripts, or verify pwd before running rmdir. Test with echo first.
Issue: Permission denied
Cause: Don't have write permission on parent directory. Solution: Check permissions with ls -ld parent_directory. Need write permission on the parent directory (not the directory being removed) to remove directories.
Issue: rmdir succeeds but directory still exists
Cause: Directory is mounted, or you're in the directory. Solution: (1) Check mount output for mounted filesystems. (2) Don't be inside the directory you're removing - cd out first. (3) Check if another process has the directory open with lsof | grep dirname.
Issue: rmdir -p removes too much
Cause: Parent directories were unexpectedly empty. Solution: This is actually working as designed, but be careful with paths. Verify the full path before using -p, especially with paths starting at root.

Related Commands

  • rm: Remove files or directories (use -r for directories, -rf for recursive force deletion)
  • mkdir: Create directories (opposite of rmdir)
  • find: Find files and directories (often used with -empty and -delete)
  • ls: List directory contents (use -A to check if directory is empty)
  • mv: Move directories (alternative to deleting)
  • tree: Display directory tree structure
  • du: Disk usage (du -sh directory checks size before removal)

Exit Status Codes

Rmdir returns the following exit status codes:
  • 0: Success - all directories were successfully removed
  • 1: Failure - one or more directories could not be removed (non-empty, doesn't exist, permission denied, etc.)

Check the exit status in scripts with $? or by using rmdir in conditional statements: if rmdir dir; then ...; fi