rm removes files and directories. There’s no recycle bin on a server. What rm deletes is gone, unless you have a backup. A few habits make it much safer.
rm [options] FILE...
Delete files
rm notes.txt
rm a.log b.log c.log
rm *.tmp
If a file is write-protected, rm asks for confirmation. -f (force) skips that prompt. It also stays silent about files that don’t exist.
Delete directories
rmdir empty-dir # only works on empty directories
rm -r old-project # a directory and everything in it
rm -rf old-project # the same, without any prompts
-r (recursive) is needed for directories. rm -rf is the command behind most “I deleted the wrong thing” stories, so treat it with care.
Safe habits
1. Look before you delete. Run ls with the same arguments first:
ls /var/www/old-site/cache/*
rm -r /var/www/old-site/cache/*
2. Use -i or -I for interactive work.
rm -i *.log # ask about each file
rm -I *.log # ask once if deleting more than 3 files or recursively
3. Prefer absolute paths, and never use unchecked variables.
rm -rf "$BUILD_DIR/"* # if BUILD_DIR is empty, this becomes rm -rf /*
Guard variables in scripts:
rm -rf "${BUILD_DIR:?BUILD_DIR is not set}/"*
${VAR:?} aborts the script if the variable is empty or unset. Also use set -u in Bash scripts. See Bash scripting basics.
4. cd and then delete is fragile. Write cd /some/dir && rm -rf ./*, never cd /some/dir; rm -rf *. With ;, a failed cd means the deletion runs in whatever directory you’re in.
5. GNU rm refuses rm -rf / by default (--preserve-root). It does not protect you from rm -rf /* or rm -rf /var.
6. Move instead of delete when you’re unsure:
mkdir -p ~/trash && mv old-config ~/trash/
Files with awkward names
rm -- -file-starting-with-dash
rm ./-file-starting-with-dash
rm "file with spaces.txt"
rm -i -- * # pick interactively
For names with unprintable characters, delete by inode number:
ls -li # find the inode number
find . -maxdepth 1 -inum 1234567 -delete
“Argument list too long”
rm *.jpg fails when the glob expands to hundreds of thousands of files. Use find:
find /path -maxdepth 1 -name '*.jpg' -delete
Delete by age, which is useful for old backups and logs:
find /var/backups/app -type f -name '*.sql.gz' -mtime +14 -print # check first
find /var/backups/app -type f -name '*.sql.gz' -mtime +14 -delete
“Operation not permitted” or “Permission denied”
- You need write permission on the directory that contains the file, not on the file itself.
- As root, a file with the immutable attribute still can’t be deleted. Check with
lsattr fileand remove the attribute withsudo chattr -i file. - Files inside a container’s volume may be owned by another UID. Use
sudo. - “Device or resource busy” means the path is a mount point. Unmount it first.
Deleted, but disk space isn’t freed
If a running process still has a deleted file open (a large log, for example), the space stays in use until the process closes it:
sudo lsof +L1 # deleted-but-open files
Restart or reload that service, or truncate the file through /proc. To empty a live log without deleting it, truncate it instead:
sudo truncate -s 0 /var/log/app/big.log
See disk full troubleshooting and lsof.
Secure deletion
shred -u file overwrites a file before deleting it. On SSDs and journaling or copy-on-write filesystems, overwriting isn’t reliable. For sensitive data, use encryption at rest and delete the keys instead.
Recovering deleted files
There’s no undo. On ext4 you can sometimes recover files with tools like extundelete or testdisk if you stop writing to the disk immediately. Don’t count on it. Backups are the real protection. See automated backups.
Quick reference
| Task | Command |
|---|---|
| Delete file | rm file |
| Delete empty dir | rmdir dir |
| Delete dir and contents | rm -r dir |
| No prompts | rm -rf dir |
| Confirm each | rm -i |
| Confirm once | rm -I |
| Delete many by pattern | find . -name '*.tmp' -delete |
| Empty a live log | truncate -s 0 file |