Short answer: to delete a file in Linux, run rm file.txt. To remove a directory and all its contents, run rm -r dirname; rmdir dirname removes only an empty one. There is no recycle bin: nothing in the shell can undo rm, so list what you are about to delete first.
rm old.log # delete a file
rm -r project/ # delete a directory and everything in it
rm -rf build/ # the same, without any prompt
rmdir empty-folder/ # delete a directory only if it is emptyThe outputs on this page come from Debian 12 with GNU coreutils 9.1, findutils 4.9.0, bash 5.2.15 and lsof 4.95, run in a scratch directory on 21 October 2026, partly as an unprivileged user. The --preserve-root, chattr, mount point and trash-cli parts follow the coreutils, e2fsprogs and trash-cli documentation and were not run on this host. Ubuntu, Rocky Linux and AlmaLinux ship the same GNU rm.
rm cheat sheet
| Task | Command |
|---|---|
| Delete a file | rm file.txt |
| Delete several files | rm a.log b.log c.log |
| Delete by pattern | rm *.tmp |
| Delete a directory and its contents | rm -r dirname |
| Same, never prompt, no error if missing | rm -rf dirname |
| Delete an empty directory | rmdir dirname |
| Delete empty directories up a path | rmdir -p a/b/c |
| Confirm every file | rm -i *.conf |
| Confirm once for a big delete | rm -I *.log |
| Show each deletion | rm -rv dirname |
| File whose name starts with a dash | rm -- -file |
| File with spaces in its name | rm "my file.txt" |
| Files older than 14 days | find /path -name '*.log' -mtime +14 -delete |
| Empty a directory, hidden files included | find dir -mindepth 1 -delete |
How do I delete a file in Linux?
rm takes one or more file names and removes them without asking and without a message. -v prints each one. A name that does not exist is an error, unless you add -f, which also makes that case succeed quietly:
$ rm -v old.log
removed 'old.log'
$ rm nofile
rm: cannot remove 'nofile': No such file or directory
$ rm -f nofile; echo $?
0Deleting a file needs write permission on the directory it is in, not on the file. A write-protected file in your own directory can be deleted, but rm asks first when it runs in a terminal:
rm: remove write-protected regular empty file 'wp'? nRoot is never asked this, and -f skips the question for everyone. Quote names with spaces: rm my file.txt tries to delete my and file.txt and fails twice with No such file or directory, while rm "my file.txt" removes the one file.
How do I remove a directory and its contents?
Plain rm refuses a directory. -r (recursive) deletes the directory, every file and every subdirectory in it:
$ rm project
rm: cannot remove 'project': Is a directory
$ rm -rv project
removed 'project/src/main.c'
removed directory 'project/src'
removed directory 'project'rm -rf adds -f: no prompts for write-protected files, no error for names that do not exist. That makes it the usual form in scripts, and the dangerous one at a prompt, because a typo in the path is executed just as quietly. For an empty directory, rmdir is the safer tool, since it refuses anything with content:
$ rmdir d
rmdir: failed to remove 'd': Directory not empty
$ rmdir -pv d/e
rmdir: removing directory, 'd/e'
rmdir: removing directory, 'd'| rm -r | rmdir | rm -d | |
|---|---|---|---|
| Removes contents | Yes, everything below | No | No |
| Directory must be empty | No | Yes | Yes |
| Removes parents too | No | With -p, while they become empty | No |
| Good for | Deleting a tree | Cleaning up after a script; a safe check that nothing is left | rm with an empty directory |
rmdir -p d/e removed d/e and then d, because d was empty once e was gone; it stops at the first parent that still has content.
Prompts: -i, -I and -f
$ rm -i a
rm: remove regular empty file 'a'? n
$ rm -I c1 c2 c3 c4
rm: remove 4 arguments? n
$ rm -rI tree
rm: remove 1 argument recursively? n-i asks for every file, which is fine for three files and useless for three thousand. -I asks once, and only when you delete more than three files or delete recursively; with three names or fewer it just runs. That makes alias rm='rm -I' in ~/.bashrc a reasonable safety net that does not get in the way. The last of -i, -I and -f on the command line wins: rm -f -i asked, rm -i -f did not, so rm -rf typed under that alias still runs without a prompt. Scripts never see the alias at all: bash does not expand aliases in a non-interactive shell.
Names with dashes, and the rm * trap
A file whose name starts with a dash looks like an option. GNU rm even tells you how to get rid of it:
$ rm -foo
rm: invalid option -- 'o'
Try 'rm ./-foo' to remove the file '-foo'.
Try 'rm --help' for more information.
$ rm -- -foo-- ends the options, so everything after it is a file name; ./-foo works too. The same mechanism makes a bare rm * risky. The shell expands * before rm runs, and GNU rm reads a file named -r as an option wherever it lands in the list:
$ ls
-r a sub
$ echo rm *
rm -r a sub
$ rm * # deletes sub/ and everything in it, without -r typed by youWrite rm ./* or rm -- * and the odd file is just a file again. Two more surprises with globs: * does not match hidden files, so rm -rf cache/* left cache/.hidden in place, and with no match at all bash passes the pattern literally, which ends in cannot remove '*.tmp': No such file or directory. To empty a directory completely but keep it, use find cache -mindepth 1 -delete.
rm -rf / and --preserve-root
GNU rm refuses to work recursively on / itself. Per the coreutils manual, --preserve-root is the default, and rm -rf / stops with it is dangerous to operate recursively on '/' unless you add --no-preserve-root. Do not rely on it:
rm -rf /*is not protected. The shell expands it to/bin /boot /etc ..., and none of those is/.- An empty variable becomes a path.
rm -rf "$DIR"/*withDIRunset isrm -rf /*. Writerm -rf "${DIR:?}"/*: bash then stops withDIR: parameter null or not setbefore rm runs. - A wrong directory is just as final.
rm -rf /var/wwwinstead of/var/www/oldis not protected by anything.
--preserve-root=all goes one step further: rm then also refuses any argument that sits on a different filesystem from its parent directory, such as a mounted backup disk.
Delete by age or pattern: find -delete
For anything more selective than a glob, let find pick the files, and run it with -print before you swap in -delete:
$ find logs -name '*.log' -mtime +14 -print
logs/a.log
logs/old/b.log
$ find logs -name '*.log' -mtime +14 -delete
$ find logs -type d -empty -delete # then the folders that are now emptyHabits that prevent the bad day
- 1List what the command will hit
Run the same path with
ls -dor the find with-print, or putechoin front of the rm. Read the list, then press the up arrow and change only the command. - 2Use absolute paths in scripts
A relative path deletes in whatever directory the script happens to run in. Cron jobs start in the user’s home directory, not where the script lives.
- 3Guard variables
"${VAR:?}"on every variable that forms a path for rm, plusset -uat the top of the script. - 4Move to a trash instead, where it fits
The trash-cli package (Debian and Ubuntu:
apt install trash-cli) addstrash-put,trash-list,trash-restoreandtrash-empty, which use the same trash folder as desktop file managers. Handy at an interactive prompt; on a server the space is only freed once you empty the trash.
Can I undo rm?
No. rm removes the name from the directory and the filesystem marks the blocks as free; there is no trash and no undo. Recovery tools for ext4 can sometimes find blocks that nothing has overwritten yet, but a server that keeps writing logs and caches makes those odds worse by the minute. What does work:
- A backup or a snapshot from before. On a VMHeaven VPS, snapshots are taken in the panel, by hand or on a daily, weekly or monthly schedule, and restored from there. One right before a cleanup costs a minute.
- A process that still has the file open. Until it closes the file, the data is still on disk and readable through
/proc. In the test, a deleted file held open by a process came back in full withcp /proc/PID/fd/3 data.db.recovered.sudo lsof +L1shows the PID and the descriptor number.
rm errors and what they mean
| Message ends with | Meaning | Fix |
|---|---|---|
| Is a directory | rm without -r on a directory | rm -r |
| Directory not empty | rmdir or rm -d on a directory with content; with rm -rf, something kept writing into it | rm -r, or stop the writer first |
| No such file or directory | Typo, unquoted spaces, or a glob that matched nothing | Check with ls; quote the name |
| Permission denied | No write permission on the directory that holds the file | See below |
| Operation not permitted | Immutable or append-only attribute, or the sticky bit (/tmp) | lsattr, then chattr -i (or -a); in /tmp, only the file owner or root deletes |
| Device or resource busy | The path is a mount point, or has one below it | findmnt, then umount |
| Read-only file system | The filesystem is mounted read-only | Read-only file system |
| invalid option | The file name starts with a dash | rm -- -name |
rm: cannot remove: Permission denied
rm: cannot remove 'f': Permission denied
rm: cannot remove 'locked/f': Permission deniedBoth files were writable by nobody but root, yet that was not the reason: the directories holding them belonged to root, and removing a name changes the directory. Inside a directory with the sticky bit, like /tmp, you may only remove your own files even with write permission on the directory; that case reports Operation not permitted instead. Check the parent with ls -ld and fix ownership or mode as described in the chmod guide, or run the rm with sudo if the files really belong to the system.
rm: cannot remove: Operation not permitted, even as root
When root gets Operation not permitted, the file usually carries the immutable attribute. Per the chattr man page, a file with +i cannot be deleted, renamed, linked or written to, by anyone, until the attribute is removed:
lsattr suspicious.conf # an 'i' in the flags means immutable
sudo chattr -i suspicious.conf
sudo rm suspicious.confAn immutable file you did not set yourself is worth a second look before you delete it: attackers use chattr +i to keep a planted cron entry or SSH key in place.
rm: cannot remove: Device or resource busy
A mounted filesystem cannot be removed from under the mount. That hits rm -r on a directory that has a mount below it, such as a Docker volume or a bind mount. findmnt -R /path lists what is mounted there. Note what happened before the error: rm descends into mounted filesystems by default and deletes what it can inside them before it fails on the mount point. Unmount first, or add --one-file-system, which makes rm skip every directory on a different filesystem from the path you gave it. On NFS, the same message can come from .nfsXXXX files, which stand in for deleted files that a process still has open; they disappear when the process closes them.
Deleted a big file, but the disk is still full?
Deleting removes the name. If a process still has the file open, typically a log file the application keeps writing, the space stays in use until the process closes it. df says full, du finds nothing. lsof +L1 lists files that have no name left:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
sleep 353107 root 3w REG 8,1 5242880 0 3542659 /srv/app/app.log (deleted)Restart or reload the process to free the space, or, for a log you no longer need, empty it through /proc with : > /proc/353107/fd/3, which took SIZE/OFF to 0 in the test while the process kept running. The lsof guide covers sorting this list on a busy server, and No space left on device walks through the rest of a full disk. Before deleting anything to make room, see what actually uses it with du and df.
Frequently asked
How do I delete a directory and everything in it in Linux?
Run rm -r dirname. It removes the directory with all files and subdirectories in it. rm -rf does the same without any prompt and without an error if the name does not exist. Check the path with ls -d first: there is no recycle bin and no undo.
What is the difference between rm -r and rmdir?
rmdir removes only empty directories and fails with Directory not empty otherwise, which makes it a safe cleanup step. rm -r removes a directory together with everything inside it. rmdir -p also removes parent directories that become empty.
Can I recover a file deleted with rm?
Not from the shell: rm has no trash and no undo, so restore it from a backup or a snapshot. One exception: while a running process still has the file open, its data can be copied back out of /proc/PID/fd/FD. sudo lsof +L1 shows the PID and the descriptor number.
Why is disk space not freed after deleting a large file?
A process still has the file open, so the kernel keeps its data until the process closes it. sudo lsof +L1 lists such deleted but open files. Restart or reload that process, or empty the file through /proc/PID/fd/FD, to get the space back.