Linux rm Command
last modified October 23, 2026
The rm (remove) command deletes files and directories. There is
no recycle bin on the command line: rm removes the directory
entry immediately, and the space is freed once no other name or process
refers to the file. Deleted data is usually gone for good, so it pays to know
exactly what a given rm command will match.
The syntax is rm [options] file.... The examples use GNU
rm from coreutils 9.1 and Bash 5.2, run in a Debian container.
The important options are -r (recursive), -f
(force), -i and -I (ask), -d (empty
directories), and -v (verbose).
Deleting a file
The simplest form deletes one file.
ls rm temp.log ls
Like most Unix commands, rm prints nothing when it succeeds.
The second ls shows that the directory is now empty.
$ ls temp.log $ rm temp.log $ ls
Deleting multiple files
Several files can be removed with one command.
rm backup1.tar missing.tar backup3.tar echo $? ls
When one of the arguments does not exist, rm reports it,
removes the remaining files, and exits with status 1. Only
backup2.tar, which was not named, is left.
$ rm backup1.tar missing.tar backup3.tar rm: cannot remove 'missing.tar': No such file or directory $ echo $? 1 $ ls backup2.tar
Deleting empty directories
Without options, rm does not remove directories. Empty
directories are removed with rmdir or rm -d.
rm empty_dir rmdir empty_dir rmdir old_project rm -d old_project
Both rmdir and rm -d refuse to delete a directory
that has any content, including hidden files. This makes them a safe way to
clean up directories that should already be empty.
$ rm empty_dir rm: cannot remove 'empty_dir': Is a directory $ rmdir empty_dir $ rmdir old_project rmdir: failed to remove 'old_project': Directory not empty $ rm -d old_project rm: cannot remove 'old_project': Directory not empty
Deleting directories recursively
The -r (-R, --recursive) option
deletes a directory with all its files and subdirectories.
tree -a temp_files rm -rv temp_files
With -v, every removed file and directory is listed. The
contents are deleted first, from the deepest level up, and the directory
itself last. Hidden files such as .hidden are deleted too.
$ tree -a temp_files temp_files ├── a.txt ├── cache │ ├── b.dat │ └── thumbs │ └── c.png └── .hidden 3 directories, 4 files $ rm -rv temp_files removed 'temp_files/cache/b.dat' removed 'temp_files/cache/thumbs/c.png' removed directory 'temp_files/cache/thumbs' removed directory 'temp_files/cache' removed 'temp_files/.hidden' removed 'temp_files/a.txt' removed directory 'temp_files'
Write-protected files and -f
When a file is write-protected and the input is a terminal, rm
asks before deleting it. The -f (--force) option
removes it without asking.
ls -l config.bak rm config.bak ls config.bak rm -f config.bak ls config.bak
The answer n keeps the file. With -f, the file is
deleted silently. -f also suppresses the error for files that
do not exist and makes the exit status 0 in that case. It does not override
the permissions of the directory, as shown later.
$ ls -l config.bak -r--r--r-- 1 jano jano 10 Oct 23 13:22 config.bak $ rm config.bak rm: remove write-protected regular file 'config.bak'? n $ ls config.bak config.bak $ rm -f config.bak $ ls config.bak ls: cannot access 'config.bak': No such file or directory
Interactive deletion
The -i option asks about every file. The -I option
asks once, when more than three files are deleted or when deleting
recursively.
rm -i error.log debug.log ls *.log rm -I *.tmp ls *.tmp
The first command deletes error.log and keeps
debug.log. The single -I question protects against
a mistyped wildcard without the tedium of confirming every file; here, the
answer n keeps all four files.
$ rm -i error.log debug.log rm: remove regular empty file 'error.log'? y rm: remove regular empty file 'debug.log'? n $ ls *.log debug.log $ rm -I *.tmp rm: remove 4 arguments? n $ ls *.tmp a.tmp b.tmp c.tmp d.tmp
Deleting files with a wildcard
Wildcards are expanded by the shell before rm runs, so the
match can be checked with echo first.
echo *.tmp rm *.tmp ls rm *.tmp rm -f *.tmp echo $?
The file my notes.tmp is matched correctly; the shell passes it
as one argument even though it contains a space. When nothing matches, Bash
passes the pattern unchanged, and rm reports that the file
*.tmp does not exist. With -f, the error is
suppressed. Do not quote the wildcard itself: rm "*.tmp" would
look for a file literally named *.tmp.
$ echo *.tmp file1.tmp my notes.tmp temp.tmp $ rm *.tmp $ ls keep.txt old_project $ rm *.tmp rm: cannot remove '*.tmp': No such file or directory $ rm -f *.tmp $ echo $? 0
Hidden files
Files whose names begin with a dot are not matched by *. They
need a pattern that starts with a dot.
ls -a rm .*.swp ls -a echo .* rm -r . ..
The pattern .*.swp removes the Vim swap files. Since Bash 5.2,
.* no longer matches . and ..; older
Bash versions and other shells expanded it to include them. GNU
rm refuses to remove . and .. in any
case, but rm -r .* is still a habit to avoid.
$ ls -a . .. .bashrc main.c .main.c.swp .notes.txt.swp $ rm .*.swp $ ls -a . .. .bashrc main.c $ echo .* .bashrc $ rm -r . .. rm: refusing to remove '.' or '..' directory: skipping '.' rm: refusing to remove '.' or '..' directory: skipping '..'
File names starting with a dash
A file name that begins with - is read as an option.
ls rm -report.txt rm -- -report.txt ls
The double dash -- marks the end of options, so everything
after it is a file name. As the error message suggests, rm
./-report.txt works too. In scripts, write rm --
"$file" for the same reason.
$ ls keep.txt old_project -report.txt $ rm -report.txt rm: invalid option -- 'e' Try 'rm ./-report.txt' to remove the file '-report.txt'. Try 'rm --help' for more information. $ rm -- -report.txt $ ls keep.txt old_project
Permissions needed to delete a file
Deleting a file changes the directory that contains it, not the file. What counts is write permission on the directory.
chmod 555 locked rm -f locked/file.txt chmod 755 locked chmod 000 locked/file.txt rm -f locked/file.txt ls locked
In a read-only directory, even rm -f fails. Once the directory
is writable, a file with no permissions at all can be deleted. In
directories with the sticky bit set, such as /tmp, users can
delete only their own files.
$ chmod 555 locked $ rm -f locked/file.txt rm: cannot remove 'locked/file.txt': Permission denied $ chmod 755 locked $ chmod 000 locked/file.txt $ rm -f locked/file.txt $ ls locked
rm removes names
A file can have several names (hard links). rm removes one
name; the data stays as long as another name exists.
echo "important" > data.txt ln data.txt data-link.txt ls -li data* rm data.txt cat data-link.txt
Both names share the same inode number, and the link count is 2. After
rm data.txt, the content is still reachable through
data-link.txt. For the same reason, the disk space of a deleted
file is not freed while a process still has it open, which is common with
large log files.
$ echo "important" > data.txt $ ln data.txt data-link.txt $ ls -li data* 2628345 -rw-r--r-- 2 jano jano 10 Oct 23 13:22 data-link.txt 2628345 -rw-r--r-- 2 jano jano 10 Oct 23 13:22 data.txt $ rm data.txt $ cat data-link.txt important
Deleting old files with find
To delete files by age, size, or other criteria, let find
select them. Always run the command without the deleting part first.
ls -l --time-style=+%F logs find logs -name "*.log" -mtime +30 find logs -name "*.log" -mtime +30 -delete ls logs
-mtime +30 matches files modified more than 30 days ago. The
first find only prints the matches; the second deletes them
with -delete, which is faster and safer than
-exec rm {} \; because it does not start a process per file.
See the find command article for details.
$ ls -l --time-style=+%F logs total 0 -rw-r--r-- 1 jano jano 0 2026-10-23 app.log -rw-r--r-- 1 jano jano 0 2026-08-01 app-old.log -rw-r--r-- 1 jano jano 0 2026-10-23 db.log -rw-r--r-- 1 jano jano 0 2026-08-01 db-old.log -rw-r--r-- 1 jano jano 0 2026-10-23 notes.txt $ find logs -name "*.log" -mtime +30 logs/db-old.log logs/app-old.log $ find logs -name "*.log" -mtime +30 -delete $ ls logs app.log db.log notes.txt
Guarding variables in rm commands
In scripts, an empty or unset variable can turn a harmless command into a destructive one.
dir=""
echo rm -rf "$dir"/*
rm -rf "${dir:?}"/*
dir=build
rm -rf "${dir:?}"/*
ls -A build
With an empty dir, "$dir"/* becomes
/*, and the echo shows that the command would
target every directory under the root. The ${dir:?} expansion
stops the command, and a non-interactive script, with an error when the
variable is empty or unset. With dir=build, the contents of
build are deleted as intended. Running scripts with set
-u catches unset variables in general. GNU rm also
refuses rm -r / unless --no-preserve-root is
given, but that does not protect /*.
$ dir=""
$ echo rm -rf "$dir"/*
rm -rf /bin /boot /dev /etc /home /lib /lib64 /media /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var
$ rm -rf "${dir:?}"/*
bash: dir: parameter null or not set
$ dir=build
$ rm -rf "${dir:?}"/*
$ ls -A build
Best practices for rm
- Preview first: Run
echoorlswith the same arguments, orfindwithout-delete, before deleting. - Prefer -I to -i: One question per command protects
against a bad wildcard without training you to answer
yautomatically. - Use rmdir for directories that should be empty: It fails instead of deleting unexpected content.
- Guard variables: Use
"${dir:?}",set -u, and--before file names in scripts. - Keep backups:
rmhas no undo; for interactive use, a trash tool such asgio trashortrash-climoves files to the desktop trash instead.
Source
In this article, we have used the rm command to delete files
and directories, handle prompts and write-protected files, deal with tricky
file names, and delete files safely in scripts.
Author
List all Linux tutorials.