Removing directories in Linux uses two commands:
rmdir
for empty directories and
rm -r
for directories with contents. The distinction matters because Linux will not let you accidentally delete a directory full of files with a command meant for empty directories. You have to be explicit about recursive deletion, which is a deliberate safety measure.
This guide covers both commands, the flags that modify their behavior, common permission errors, and the safety considerations around
rm -rf
that every server administrator should understand.
Removing empty directories with rmdir#
rmdir
removes directories that contain no files or subdirectories. If the directory has anything in it,
rmdir
refuses and prints an error.
rmdir /home/user/old-project
If the directory is empty, it is removed silently. If it contains anything:
rmdir: failed to remove '/home/user/old-project': Directory not empty
This is intentional.
rmdir
is the safe way to clean up directories you expect to be empty. If something is still in there, you want to know before deleting.
Remove multiple empty directories
rmdir dir1 dir2 dir3
All three are removed if they are empty. If any one of them is not empty,
rmdir
prints an error for that directory and removes the others.
Remove nested empty directories with -p
rmdir -p /home/user/a/b/c
This removes
c
, then
b
, then
a
, working from the deepest directory up, but only if each directory is empty after the one below it is removed. If
b
contains other files besides the now-removed
c
,
rmdir
stops at
b
and prints an error.
The
-p
flag is useful when you created a nested directory structure and want to clean it up in one command instead of removing each level individually.
Removing directories with contents using rm -r#
When a directory contains files or subdirectories, you need
rm
with the
-r
(recursive) flag. This removes the directory and everything inside it, no matter how deeply nested.
rm -r /home/user/old-project
This deletes
old-project
and every file and subdirectory it contains. There is no undo. The files do not go to a trash bin. They are gone.
What -r does
The
-r
flag (also written as
-R
or
--recursive
) tells
rm
to descend into directories and remove their contents before removing the directory itself. Without
-r
,
rm
only operates on files:
rm /home/user/old-project
rm: cannot remove '/home/user/old-project': Is a directory
rm
refuses to remove a directory without the recursive flag. This prevents accidental directory deletion when you meant to delete a single file.
Interactive mode with -ri
rm -ri /home/user/old-project
The
-i
flag prompts for confirmation before deleting each file. On a directory with hundreds of files, this gets tedious fast, but it is useful when you want to review what is being deleted. You can type
y
for yes or
n
for no at each prompt.
Verbose mode with -rv
rm -rv /home/user/old-project
The
-v
flag prints each file and directory as it is deleted. This gives you a log of everything that was removed, which is useful for auditing or verifying that the right things were deleted.
removed '/home/user/old-project/file1.txt'
removed '/home/user/old-project/subdir/file2.txt'
removed directory '/home/user/old-project/subdir'
removed directory '/home/user/old-project'
rm -rf: force removal#
The
-f
flag suppresses confirmation prompts and ignores nonexistent files. Combined with
-r
, it removes everything without asking questions.
rm -rf /home/user/old-project
This is the most commonly used form for directory deletion. It removes the directory, all contents, and does not prompt even if files are read-only or if some files do not exist. It also does not print an error if the target directory does not exist, which makes it useful in scripts where the directory may or may not be present.
When to use rm -rf
- Removing build artifacts and temporary directories in deployment scripts
- Cleaning up old backups or log directories
- Deleting a WordPress installation or plugin directory during migration
- Removing cached files that need to be regenerated
When NOT to use rm -rf
Never run
rm -rf /
or
rm -rf /*
. This attempts to delete every file on the entire system. Modern Linux distributions have a safeguard (
--preserve-root
enabled by default) that prevents
rm -rf /
from executing, but
rm -rf /*
bypasses this protection because the shell expands
/*
to a list of individual paths before
rm
sees them.
Never run
rm -rf
with unquoted variables. This is one of the most dangerous patterns in shell scripting:
# DANGEROUS - if $DIR is empty, this becomes rm -rf /
rm -rf $DIR/
# SAFER - quotes prevent empty variable from expanding to /
rm -rf "$DIR"/
# SAFEST - check that the variable is set before using it
if [ -n "$DIR" ]; then
rm -rf "$DIR"
fi
If
$DIR
is empty or unset,
rm -rf $DIR/
becomes
rm -rf /
. With quotes, an empty
$DIR
becomes
rm -rf "/"
, which is still caught by
--preserve-root
. But the defensive check is better practice.
Never run
rm -rf
with relative paths you have not verified. Before running
rm -rf ../something
, confirm your current directory with
pwd
. A wrong assumption about your working directory means you delete the wrong thing.
Think before adding
sudo
.
sudo rm -rf
runs with root privileges, which means it can delete files you do not own, including system files. If you need
sudo
to delete something, ask yourself why. If the answer is “I do not own these files,” that is a signal to verify you are deleting the right thing.
Permission denied errors#
Cannot remove: Permission denied
rm: cannot remove '/var/www/html/cache': Permission denied
This means the current user does not have write permission on the parent directory. To delete a file or directory, you need write permission on the directory that contains it, not on the file itself.
Check the permissions:
ls -la /var/www/html/
Look at the permissions on the
html
directory (the parent of
cache
). If you do not have write permission, you cannot remove anything inside it.
Fix options:
Use
sudo
if you have the right to:
sudo rm -rf /var/www/html/cache
Or change the permissions on the parent directory:
chmod u+w /var/www/html/
rm -rf /var/www/html/cache
For a full explanation of how Linux permissions work and what the numeric values mean, see Linux file permissions: chmod and chown explained.
Cannot remove: Read-only file system
rm: cannot remove '/mnt/backup/old-data': Read-only file system
The filesystem is mounted as read-only. This happens with backup mounts, NFS shares configured as read-only, and filesystems that were remounted read-only after a disk error.
Check the mount:
mount | grep /mnt/backup
If it shows
ro
(read-only), you need to remount as read-write:
sudo mount -o remount,rw /mnt/backup
Or if the read-only mount is intentional (backup media, snapshot), you should not be deleting from it.
Cannot remove: Device or resource busy
rm: cannot remove '/var/log/active.log': Device or resource busy
A process has the file or directory open. You cannot delete it while something is using it. Identify what is using it:
lsof /var/log/active.log
This shows which process has the file open. You need to stop that process or wait for it to release the file before you can delete it.
Cannot remove: Operation not permitted (immutable attribute)
rm: cannot remove '/var/www/html/important.conf': Operation not permitted
Even with root access, this error means the file has the immutable attribute set. The immutable attribute prevents any modification or deletion, even by root.
Check for the attribute:
lsattr /var/www/html/important.conf
If you see an
i
in the output, the file is immutable. Remove the attribute first:
sudo chattr -i /var/www/html/important.conf
Then delete normally. The immutable attribute is sometimes set intentionally on critical files to prevent accidental deletion, so verify that removing it is appropriate before proceeding.
Safely removing WordPress directories#
WordPress hosting involves frequent directory cleanup: clearing cache directories, removing old plugins, deleting abandoned themes, and cleaning up backup files. Here are the common operations and the safe way to do them.
Remove a plugin directory
rm -rf /var/www/html/wp-content/plugins/plugin-name
Always deactivate the plugin through wp-admin or WP-CLI before removing its directory. Removing a plugin directory while it is active can cause PHP fatal errors if WordPress tries to load files that no longer exist.
wp plugin deactivate plugin-name
rm -rf /var/www/html/wp-content/plugins/plugin-name
Clear the WordPress cache directory
rm -rf /var/www/html/wp-content/cache/*
Note the
/*
at the end. This removes the contents of the cache directory without removing the directory itself. Some caching plugins expect the cache directory to exist and will error if it is missing.
Remove an old WordPress installation during migration
# Back up first
tar -czf /home/user/backup-before-delete.tar.gz /var/www/html/
# Then remove
rm -rf /var/www/html/*
Always create a backup with tar before deleting an entire WordPress installation. The backup takes seconds to create and can save hours if something goes wrong.
Removing directories matching a pattern#
Delete directories by name with find
find /var/www -type d -name "cache" -exec rm -rf {} +
This finds all directories named
cache
under
/var/www
and removes them. The
-type d
flag limits the search to directories only.
For WordPress sites, this is useful for clearing cache directories:
find /var/www -type d -name "wp-cache" -exec rm -rf {} +
Delete empty directories with find
find /home/user/projects -type d -empty -delete
The
-empty
flag matches only empty directories, and
-delete
removes them. This is a clean way to prune empty directories from a tree without affecting anything that contains files.
Preview before deleting
Always preview what
find
will match before adding
-exec rm
or
-delete
:
# See what would be deleted
find /var/www -type d -name "cache"
# Then delete
find /var/www -type d -name "cache" -exec rm -rf {} +
For complex find patterns, see Linux find command: how to find files and processes.
Removing directories over SSH#
If you are managing a remote server, you run the same commands through an SSH session:
ssh user@server "rm -rf /var/www/html/wp-content/cache"
This connects, runs the command, and disconnects. For directories with many files, the deletion may take a while. If you disconnect during a long deletion, the process continues on the server.
For large directories (millions of files),
rm -rf
can be slow because it processes each file individually. An alternative for very large directories:
mkdir /tmp/empty-dir
rsync -a --delete /tmp/empty-dir/ /var/www/html/cache/
rmdir /var/www/html/cache
This uses
rsync
to synchronize the target with an empty directory, which is faster than
rm -rf
for directories with hundreds of thousands of files because
rsync
handles the unlinking more efficiently. For more on rsync, see How to sync directories with rsync.
Quick reference#
# Remove an empty directory
rmdir dirname
# Remove a directory and all contents
rm -r dirname
# Remove without prompts (force)
rm -rf dirname
# Remove with verbose output
rm -rv dirname
# Remove with confirmation for each file
rm -ri dirname
# Remove nested empty directories
rmdir -p a/b/c
# Find and remove directories by name
find /path -type d -name "dirname" -exec rm -rf {} +
# Find and remove empty directories
find /path -type d -empty -delete
# Check permissions before removing
ls -la /parent/directory/
| Command | What it does | When to use |
|---|---|---|
rmdir dir
| Remove empty directory | Cleaning up known-empty directories |
rm -r dir
| Remove directory and contents | General directory deletion |
rm -rf dir
| Force remove without prompts | Scripts and automation |
rm -rv dir
| Remove with verbose log | When you want a deletion record |
rm -ri dir
| Remove with per-file confirmation | When you want to review before deleting |