Files and directories — creating, moving, copying, deleting
The commands that actually change the filesystem — and the one that deserves real caution, since rm has no undo, no trash can, and no confirmation dialog by default. A small, deliberate habit here prevents the single most common command-line disaster.
Beginner
3 min read
Creating: touch, mkdir
touch creates a new, empty file (or updates an existing file's
modification timestamp if it already exists):
$ touch notes.txt
mkdir creates a new directory:
$ mkdir project$ mkdir -p project/src/utils # -p creates every missing parent directory too
Without -p, mkdir project/src/utils fails outright if project or
project/src doesn't already exist — -p creates the whole chain in one
command instead of requiring three separate ones.
Copying and moving: cp, mv
cp copies a file (the original stays where it was):
mv moves a file — and, notably, this is also how you rename something,
since renaming is really just "moving" a file to a new name in the same
location:
$ mv notes.txt todo.txt # rename: same location, new name$ mv todo.txt project/notes/ # actual move: new location
Deleting: rm — no undo, no trash can, by default
rm deletes a file permanently — there's no "restore from recycle bin"
step to fall back on if you get it wrong:
$ rm notes.txt$ rm -r project/ # -r (recursive) required to delete a directory
This absence of a safety net is exactly why rm -rf (recursive, force —
-f suppresses even the few confirmation prompts rm sometimes shows)
combined with a wrong or unintended path is one of the most infamous, real
command-line disasters — deleting an entire directory tree with no way to get
it back.
The habit that actually prevents rm disasters
Before running any rm (especially with -r, and especially with a wildcard
like *), run ls on the exact same path first and actually read the
output — confirming what will be deleted before committing to deleting it,
rather than trusting a path you typed from memory. This single habit — verify,
then act, for anything irreversible — is worth applying generally, not just
to rm: it's the same discipline this app's other domains apply to
destructive git operations and production deploys.
$ ls old-logs/*.tmp # see exactly what would be deletedold-logs/2026-01.tmp old-logs/2026-02.tmp$ rm old-logs/*.tmp # now delete it, having confirmed the match
Wildcards: matching multiple files at once
* matches any sequence of characters, letting a single command operate on
many files that share a pattern:
$ rm *.tmp # every file ending in .tmp, in the current directory$ cp *.jpg photos/ # copy every .jpg file into photos/
Wildcards are exactly why the "check with ls first" habit matters most —
a slightly-wrong wildcard pattern can match far more (or fewer) files than
intended, and rm will act on whatever it actually matched, correctly or not.