Linux & Bash · Part I · Module 3 · Creating and Changing Files and Directories
Deleting Things, and Why There Is No Undo
Deleting is an ordinary thing to do and you will do it constantly — clearing out old results, removing a file you created by mistake, cleaning a work area before starting again. What makes it worth its own careful chapter is a single property that sets it apart from everything else in this course: it cannot be reversed. There is no recycle bin, no trash folder, no confirmation dialogue and no command that puts it back. This chapter teaches the commands, shows the three shapes that real accidents actually take, and gives you a routine that makes those accidents structurally impossible rather than merely unlikely.
Foundation18 min readLinuxPart IFundamentalsFilesData Safety
Part I · Module 3 · Chapter 3.3 · Deleting Things
1. What Deleting Actually Does
Chapter 2.1 described a directory as a container of entries, where each entry is a name paired with the thing it points at. Deleting is best understood at that level:
rmremoves an entry from a directory. When the last name pointing at a file is gone, the file's data is no longer reachable.
That framing matters because it explains the limits of what you are about to read. Chapter 2.5 introduced the link count — the number of names pointing at the same data — and Module 6 goes into it properly. For almost everything you will do, there is one name, and removing it removes your access to the contents.
2. There Is No Undo
A graphical file manager on Linux usually has a trash folder. rm does not use it. Neither does any command in this chapter.
There is no recycle bin, no confirmation by default, and no command that reverses the operation. Specialist recovery tools exist, they are unreliable, they require the filesystem to be left alone immediately, and on a shared or networked filesystem they are typically not an option at all.
The practical position to adopt: treat every deletion as permanent, because it is.
3. rm — Removing Files
$ pwd
/home/engineer/project
$ ls
docs notes.txt rtl scripts sim
$ rm notes.txt
$ ls
docs rtl scripts simNo output. Chapter 1.2's convention again: these tools stay quiet on success. The file is gone.
Several at once, since rm takes any number of operands:
$ rm draft1.txt draft2.txt draft3.txtEvery path form works, which is also every path form's chance to be wrong:
$ rm sim/run1/old.log # relative — depends on where you are
$ rm /tmp/scratch.txt # absolute — the same file from anywhere
$ rm ../spare/notes.txt # up and acrossWhen it cannot:
$ rm missing.txt
rm: cannot remove 'missing.txt': No such file or directory
$ echo $?
1A reported failure and a non-zero status — the honest case, and one that -f in §6 takes away.
4. rmdir — The Only Safe Delete
$ mkdir empty_dir
$ rmdir empty_dirrmdir removes a directory, and it has a property no other command here has:
$ rmdir sim
rmdir: failed to remove 'sim': Directory not emptyIt refuses if the directory is not empty. It cannot delete anything you did not explicitly name, because it cannot delete contents at all.
That refusal is not a limitation to work around. It is a guarantee, and it is the reason to reach for rmdir on purpose:
If you believe a directory is empty and you want it gone,
rmdirwill do it — and if you were wrong, it will tell you instead of destroying the contents.
rm -r in the next section would have deleted everything inside without comment. Choosing rmdir is choosing to be told when your belief is wrong.
5. rm -r — Removing a Directory and Its Contents
rm on its own will not delete a directory:
$ rm sim
rm: cannot remove 'sim': Is a directoryA safe refusal, like cp's in Chapter 3.2. To remove a directory and everything in it:
$ rm -r sim/run1-r is recursive: descend through the directory and remove what is found, all the way down, then remove the directory itself.
This is where the danger begins, and it is worth being precise about why. rm file.txt affects exactly what you named. rm -r directory affects everything underneath it, however much that is, and you will typically not have looked at most of it. The command is the same length; the blast radius is not.
6. -f, and Why rm -rf Deserves Its Reputation
$ rm -f missing.txt
$ echo $?
0-f is force: do not ask, and do not complain about things that are not there. Notice the exit status — the command "succeeded" at removing a file that never existed.
That is genuinely useful in one situation: cleaning up when you do not care whether the thing was there. It is also how a typo stops being visible. With -f, these two look identical from the outside:
$ rm -f sim/run1/old.log # removed the file
$ rm -f sim/run1/old.lgo # removed nothing, said nothing, exit 0Combine the two options and you get the command with the worst reputation in Unix:
$ rm -rf some_directoryRecursive means it goes everywhere below the path. Force means it never stops to ask and never complains. Together they will remove whatever the path resolves to, completely, without a word.
The command is not evil and you will use it. What makes it dangerous is that all of its safety has been switched off at exactly the moment the consequences are largest — so the safety has to come from you, before you press Enter.
7. The Three Shapes a Real Accident Takes
Accidents are not random. They have shapes, and all three are recognisable in advance.
Shape 1 — the right command in the wrong directory
$ pwd
/home/engineer/project/sim/run1
$ rm -rf logs # intended: the logs of this runCorrect. Now the same command an hour later, after moving:
$ pwd
/home/engineer/project
$ rm -rf logsIf a logs directory exists here too, it is gone. The command was right; the location was not. This is Chapter 2.2's lesson — a relative path means nothing without a starting point — arriving with permanent consequences.
Shape 2 — the pattern that matched more than you pictured
$ rm -rf run_*You pictured run_1 and run_2. The directory also contained run_archive, which you had forgotten about. The pattern matched it too.
Chapter 3.5 explains exactly how patterns are expanded and gives the technique that makes this impossible to get wrong. For now, recognise the shape: the command did precisely what you typed, and what you typed covered more than you had in mind.
Shape 3 — the path that was not what you thought
The worst version involves a path built from a value rather than typed out, where the value turns out to be empty and the path collapses to something far larger than intended.
You do not have the syntax for this yet — it needs variables, which are Module 8 — and this chapter is deliberately not teaching it early. But the shape is worth carrying now, because it is the mechanism behind most of the famous stories:
A deletion whose target is computed rather than typed can resolve to something enormous if part of the computation produces nothing.
Module 8 introduces variables; Module 20 gives the guard that makes this specific accident impossible and treats it as a required practice rather than advice. Until you write anything that computes a path to delete, you are not exposed to it.
8. The Routine
The whole of this chapter's practical content is one habit, and it defeats all three shapes above.
In practice:
$ pwd
/home/engineer/project/sim
$ ls -d run_*
run_1 run_2 run_archiveThere it is — run_archive, which you had not pictured. The check cost one command and found Shape 2 before it could do anything.
Narrow the target and look again:
$ ls -d run_[12]
run_1 run_2That is the set you meant. Now delete it, reusing the same path:
$ rm -rf run_[12]Chapter 2.5's -d is doing real work in those checks: without it, ls would list the contents of each matching directory rather than showing you the set of things about to be removed. You want the list of targets, not their insides.
9. Four More Protections Worth Having
rm -i asks about each file.
$ rm -i notes.txt
rm: remove regular file 'notes.txt'? yGood for a handful of files, useless for hundreds — and a prompt you answer a hundred times is a prompt you stop reading.
rmdir instead of rm -r when you believe a directory is empty. §4. Let the command check your belief.
-- before a name that might begin with a dash. Chapter 1.5 introduced this, and here it has teeth: a file named -rf passed to rm without -- would be read as options.
$ rm -- -weird-name.txtPrefer deleting a named directory to deleting its contents. rm -rf run_1 names one thing. rm -rf run_1/* is a pattern, which is Shape 2 waiting to happen — and it misses hidden entries anyway, per Chapter 2.6.
10. What You Cannot Delete, and Why That Is Good
$ rm /etc/os-release
rm: cannot remove '/etc/os-release': Permission deniedMost of the tree is not yours. On a shared machine that is the system protecting itself and everybody else — Chapter 2.1's point that /bin and /etc belong to the distribution rather than to you.
Treat Permission denied on a delete as information, not an obstacle. If you genuinely need something removed from a shared area, the right move is to ask whoever administers it, not to find a way around the refusal.
11. Why This Matters in Engineering Work
Deleting is routine in engineering work for an unglamorous reason: jobs that produce output fill disks, and full disks stop everybody's work, not just yours.
So cleaning up is a real and regular task — and it is performed on directories full of files you did not individually inspect, which is exactly the condition Shape 2 needs. Two habits carry over directly:
Delete by run, not by pattern. Chapter 3.1's one-directory-per-run convention pays off here: rm -rf sim/run_042 names a single, complete, self-contained thing. There is no pattern to over-match and nothing of anyone else's inside it.
Check before cleaning, every time. ls -d on the same path, then delete. The one time it tells you something unexpected pays for every time it did not.
There is a third habit that belongs here and is easy to forget: if something failed, archive before you clean. The evidence you need to understand a failure is usually in the directory you are about to remove, and Chapter 3.6 is the command for keeping it. Part II treats disk pressure, retention and cleanup as a subject in its own right.
12. Practice
The tree:
/home/engineer/project
├── docs
│ └── readme.md
├── rtl
│ ├── alu.sv
│ └── counter.sv
└── sim
├── run_1
│ └── out.log
├── run_2
│ └── out.log
└── run_archive
└── keep.logQuestion 1. rm sim fails. What is the message, and why is the refusal helpful?
Question 2. You want sim/run_1 and everything in it gone. Write the command, then write the command you would run first and say exactly what you would be looking for in its output.
Question 3. You believe docs is empty and want it removed. Which of rmdir docs and rm -r docs should you use, and what happens with each if you are wrong?
Question 4. From /home/engineer/project/sim, you run rm -rf run_*. List every directory that is destroyed. Which one is the surprise, and which shape from §7 is this?
Question 5. rm -f results.txt prints nothing and exits 0. Give the two different situations that produce exactly this outcome, and explain why you cannot tell them apart.
Question 6. Your working directory is /home/engineer/project and you run rm -rf logs, intending the logs of a particular simulation run. What has gone wrong, and which Module 2 chapter explains it?
Question 7. Why does running ls -d with the same path tell you reliably what rm -rf would remove? Which component makes the two selections identical?
Question 8. Why is rm -rf run_1 a safer habit than rm -rf run_1/*, even though both appear to clear the same directory?
13. Remember
- There is no undo and no recycle bin. Treat every deletion as permanent, because it is.
rmremoves a file. It refuses to remove a directory, which is a safe refusal.rmdirremoves a directory only if it is empty — the one delete on the system that checks your belief before acting. Use it deliberately.rm -rremoves a directory and everything beneath it, which is usually far more than you have looked at.-fsuppresses both the questions and the complaints, so a typo and a success look identical and both exit 0.- Accidents are not typos. They are correctly typed commands aimed at the wrong target: the wrong directory, a pattern that matched more than you pictured, or a computed path that collapsed.
- The routine beats all three:
pwd, thenls -don the identical path, read every line, and only then swaplsback torm. - The swap works because the shell expands the line the same way for both commands. The listing is the delete's selection, shown rather than destroyed.
- Name one directory rather than pattern its contents.
rm -rf run_1has no pattern to over-match. Permission deniedis the system working. Ask the owner rather than routing around it.- In a script, the target is usually a variable — and Chapter 20.4 measures what
rm -rf "$dir/"builds when that variable turns out to be empty.
The next chapter is about the other half of Shape 2: which characters in a file name the shell treats as instructions rather than as part of the name — starting with the one that silently turns a single file into two.
Where this fits
Part of the Linux & Bash curriculum.
