Files & Directories: Make, Copy, Move, Delete
- Create directories (including nested ones) and files with mkdir -p and touch
- Copy files and whole directory trees with cp / cp -r, and know what -i protects you from
- Move AND rename with mv — one command, two jobs — without clobbering things
- Delete deliberately with rm and rmdir, understand -r, and treat -rf with earned respect
- Act on many files at once with wildcards (*, ?, [..]) — and preview a glob before you trust it
Making things: mkdir and touch
Create directories (nested in one stroke) and empty files.
Quick grounding before the commands. Everything on the system is one of two things: a file (content — text, an image, a program) or a directory (a container that holds files and other directories). That's the whole vocabulary. In the last lesson you learned to walk that tree of directories with
pwd,ls, andcd; this lesson is about shaping it — creating, duplicating, relocating, and removing the files and directories in it. Same tree, now with tools to change it.It starts with just two creation commands that cover nearly everything:
mkdir name— make a directory right here.mkdir -p a/b/c— make a whole nested chain in one command.-p(for "parents") creates every missing level along the way, and — handily — doesn't complain if some of them already exist.touch name— create an empty file. (On a file that already exists,touchinstead just updates its timestamp to now — which is the original reason for the name, and occasionally useful.)
So standing up a project skeleton is just a couple of lines:
mkdir -p project/src project/docs, thentouch project/src/main.txt. Noticemkdirhappily takes several directory names at once.mkdir -p workshop/tools/small && ls -R workshopworkshop: tools workshop/tools: small workshop/tools/small:
- -p
- create parent directories as needed; stay quiet if they already exist
-pbuilt three nested levels —workshop, thentoolsinside it, thensmall— in a single command, andls -R(recursive) walks the whole chain to prove it exists. Try that without-pandmkdir workshop/tools/smallfails outright, because plainmkdirwill only create the last directory and refuses when its parents are missing.Check yourself
You need the nested path projects/2026/reports to exist, and none of it does yet. What's the one-command way?
Copying: cp and cp -r
Duplicate files and whole directory trees — without clobbering things by accident.
cp(copy) makes a duplicate; the original always stays put, so after acpthere are two of the thing. The shapes you'll use:cp source dest— copy a file. Ifdestis an existing directory, the copy lands inside it keeping its name; ifdestis a filename, that becomes the copy's new name.cp -r dir1 dir2— copy a whole directory tree (recursive). Plaincprefuses directories on purpose — the-ris you saying "yes, everything inside too."cp -i— interactive: ask before overwriting.
That last one guards a real trap, so let's see it, not just read about it.
Example — not runnable on your lab box
cp notes.txt notes.bak && lsnotes.bak notes.txt
- -r
- recursive — copy a directory and everything inside it
- -i
- interactive — prompt before overwriting an existing destination
- -p
- preserve mode, ownership, and timestamps on the copy
A plain file copy: notes.txtis untouched andnotes.bakis a fresh duplicate of it. Because the destination was a filename (not a directory), the copy took that name. This is the everyday backup-before-I-edit move.Example — not runnable on your lab box
mkdir -p archive && cp notes.txt archive && ls archivenotes.txt
This is the distinction that trips everyone up once: when the destination is an existing directory ( archive), the copy lands inside it keeping its original name — so you getarchive/notes.txt. Compare to the previous example, where the destination was a filename (notes.bak) and the copy took that name instead. Same command, two behaviours, decided entirely by whether the destination is a directory or a name.Check yourself
cp refuses to copy your directory with 'omitting directory'. Which flag copies directories and everything inside them?
Moving and renaming: mv is both
Internalise that moving and renaming are the same operation.
Here's a small realisation that makes
mv(move) click: moving and renaming are the same thing. To the filesystem, a file's name is part of its path, so changing where it lives and changing what it's called are one operation. One command, three uses:- Move:
mv report.txt archive/— same name, new place. - Rename:
mv report.txt report-final.txt— same place, new name. - Both at once:
mv report.txt archive/report-final.txt.
Unlike
cp, aftermvthere's still only one file — it relocated, it wasn't duplicated. And the same silent-overwrite trap applies:mv a breplaces an existingbwithout asking, somv -iis the careful version.touch draft.txt && mv draft.txt final.txt && lsfinal.txt
- -i
- interactive — prompt before overwriting an existing destination
A rename is just mvwith a new name as the destination. Noticedraft.txtis gone from the listing entirely — the file itself becamefinal.txt, contents completely untouched. Nothing was copied; the one file simply has a new name now.Check yourself
What command renames meeting-notes.txt to 2026-07-notes.txt?
- Move:
Deleting: rm, rmdir, and the -rf conversation
Delete on purpose, never by surprise.
Before any syntax, the one fact that shapes everything about deletion: `rm` is permanent. There is no recycle bin, no undo, no "restore from trash." The moment
rmreturns, the file is genuinely gone. Internalise that and the careful habits below will feel natural rather than fussy.rm file— delete a file.rm -i file— ask "really?" first (training wheels worth wearing early).rmdir dir— delete an empty directory only; it refuses if anything is inside. That refusal is a safety feature, not a limitation.rm -r dir— delete a directory and everything inside it, recursively.rm -rf dir— the same, plus-f(force), which suppresses errors and prompts.
rm -rfhas completely legitimate uses — you'll type it on throwaway build directories forever. What keeps it safe isn't avoiding it; it's one habit: read the line before you press Enter. Ask yourself: what exactly does this path match, and am I standing where I think I am (pwd)?rmdir workshop/tools/small && echo removedremoved
- -r
- recursive — delete a directory and all its contents
- -i
- interactive — confirm each deletion
- -f
- force — suppress prompts and 'no such file' errors (use with care)
rmdirremovedsmallbecause it was empty. Try it on a directory with contents and it stops you cold —rmdir: failed to remove 'tools': Directory not empty. That error isrmdirprotecting you: to delete a non-empty directory you must switch torm -rand consciously accept that everything inside goes too.Check yourself
rmdir refuses to delete your 'old-project' directory because it isn't empty. Which command deletes the directory AND its contents?
Wildcards: acting on many files at once
Understand globbing — and that the SHELL expands it before the command ever runs.
Doing things one file at a time is fine for one file. Wildcards (also called globs) let you act on many at once by matching names against a pattern:
*— any number of any characters:*.logmatches every name ending in.log.?— exactly one character:report-?.txtmatchesreport-1.txtbut notreport-10.txt.[..]— one character from a set:report-[12].txtmatchesreport-1andreport-2only.
Now the single most important idea in this whole lesson, because it prevents disasters: *the shell expands the pattern first, then runs the command. When you type `rm .log
,rmnever sees*.logat all — the shell replaces it, sormactually receivesrm access.log error.log old.log`. The command has no idea a wildcard was ever involved.Example — not runnable on your lab box
ls *.logaccess.log error.log install.log
This is the dry run, and it's the professional's safety move. Because the shell expands *.logthe same way for every command, this list is exactly whatrm *.logwould delete. If a name you didn't expect appears here — a file you meant to keep — you just caught it, for free, before anything was destroyed. Fix the pattern, then run the real command.Check yourself
Before running 'rm *.bak', what command shows you exactly which files that pattern will match?
Now do it — build, copy, prune
Read it, then run it. Do a full create → copy → rename → preview → delete cycle in your live terminal.
You have a real, throwaway sandbox to the right — the perfect place to make these commands muscle memory. Run this little lifecycle end to end and watch each step change what
lsreports. If anything goes sideways, reset the lab and go again; that's exactly what it's for.mkdir -p lab/src && touch lab/src/a.txt lab/src/b.txt && ls lab/srcBuild a small tree and drop two empty files in it. You should see a.txtandb.txt. Onemkdir -pand onetouch(with two names) and the scaffold exists.cp -r lab lab-backup && lsCopy the whole labtree tolab-backup— note the-r, becauselabis a directory. Now there are two independent trees; editing one won't touch the other.mv lab/src/a.txt lab/src/first.txt && ls lab/srcRename a.txttofirst.txtin place.a.txtdisappears from the listing andfirst.txttakes its spot — same file, new name.ls lab/src/*.txt && rm lab/src/*.txt && ls lab/srcThe safe deletion pattern in one line: FIRST list what *.txtmatches (preview), THEN delete it, THEN confirm the directory is empty. In real work you'd read that preview and pause before therm— here you can watch the whole move at once.
- mkdir -p builds whole nested paths in one command (and is safe to re-run); touch makes empty files.
- cp duplicates (add -r for directories, -p to preserve metadata); mv relocates AND renames — the same operation to the filesystem.
- cp and mv overwrite existing destinations silently — -i asks first; there is no undo for a clobbered file.
- rm is permanent: no recycle bin. rmdir only deletes empty dirs (a feature); rm -r takes the whole tree; read the line — especially the spaces — before -rf.
- Globs (*, ?, [..]) are expanded by the SHELL before the command runs — preview with ls/echo to see exactly what a pattern matches.
- The four habits: preview globs, check destinations, respect rm, and pwd before anything destructive.
| Task | Command |
|---|---|
| Make a directory / nested path | mkdir name · mkdir -p a/b/c |
| Make an empty file | touch name |
| Copy a file / a directory | cp src dest · cp -r dir dest |
| Ask before overwriting | cp -i · mv -i |
| Move / rename | mv thing place/ · mv old new |
| Delete a file / with confirmation | rm file · rm -i file |
| Delete empty dir / whole tree | rmdir dir · rm -r dir |
| Match many / one char / a set | *.log · report-?.txt · file[12].txt |
| Preview what a glob matches | ls pattern (or echo pattern) |
