# The Terminal & Shell, Explained

> What the black window actually is, the difference between the terminal and the shell, the everyday commands worth knowing, and the real power features - pipes, redirection, wildcards, and PATH - that make typing beat clicking.


---

# The Terminal & Shell, Explained

That black window with the blinking cursor scares a lot of people, and that's a completely fair reaction.
Nobody is born knowing what to type into it, and most of us were handed it with no explanation - "open a
terminal and run this" - as if that were a sentence anyone could act on. The fear isn't about the window;
it's about not knowing what it *is* or what your typing actually *does*. This guide fixes exactly that.

By the end you'll know what the terminal really is, what the shell really is (they're two different
things, and confusing them is the root of a lot of bewilderment), the handful of commands you'll reach for
every day, and the few power features that make experienced developers prefer typing to clicking. You'll
be able to drive your computer by hand - calmly, on purpose, knowing what each line does before you press
Enter.

> ⏭️ This guide assumes you already know roughly what an operating system is. If "the OS" is fuzzy, the
> sibling guide [/guides/what-an-operating-system-is](/guides/what-an-operating-system-is) is the place
> to start - then come back here.

## How to read this

- **Want it to finally make sense?** Read in order - each phase builds on the last. Phase 1 installs the
  mental model, and everything after it leans on that picture.
- **Already comfortable, just need the commands?** Jump to [Phase 2: The Essential Commands](02-essential-commands.md)
  for the everyday toolkit, then [Phase 3](03-pipes-redirection-wildcards-path.md) for the power features.

## The phases

1. **[What the Terminal and Shell Actually Are](01-terminal-vs-shell.md)** - the window vs. the program
   reading your commands, the prompt, the read-eval-print loop, and why a text interface exists at all.
2. **[The Essential Commands](02-essential-commands.md)** - the anatomy of a command, then `pwd`, `ls`,
   `cd`, `cat`, `less`, `mkdir`, `cp`, `mv`, and `rm`, each with a real transcript and the gotchas that
   bite beginners.
3. **[The Real Power: Pipes, Redirection, Wildcards & PATH](03-pipes-redirection-wildcards-path.md)** -
   `|`, `>`/`>>`, `*`, and how the shell decides which program a command name maps to.

> Deliberately deferred to follow-up guides: writing shell *scripts* (saving commands in a file to rerun),
> environment-variable management beyond PATH, SSH and remote sessions, and shell customization (aliases,
> prompts, dotfiles). This guide gets you driving the computer by hand first; scripting is the next step
> once that's comfortable.


---

# What the Terminal and Shell Actually Are

Before a single command, let's clear up the thing that quietly confuses almost everyone: people say
"terminal," "shell," "command line," and "console" as if they're one thing. They're not, and once you can
tell them apart, the whole black window stops feeling like an intimidating blob and becomes a couple of
simple, separate pieces you can reason about.

## Two things, not one: the window and the program inside it

Picture what's really happening when you open that black window. There are two distinct pieces stacked
together:

```mermaid
flowchart TD
  Terminal[The terminal, the window<br/>draws text, captures keystrokes] --> Shell[The shell, a program<br/>bash / zsh / pwsh - reads, runs, prints]
  Shell --> OS[The operating system<br/>actually runs the programs]
```

**What the terminal actually is.** The **terminal** (or "terminal emulator") is the *window* - a fairly
dumb but useful program whose entire job is to show text on the screen and capture the keys you press. It
doesn't understand a single command you type. It's a pane of glass with a keyboard attached - the
screen-and-keyboard, nothing more.

**What the shell actually is.** Inside that window runs a second program: the **shell**. *This* is the
part with the brains. The shell reads the line you type, figures out what you meant, asks the operating
system to actually do it, and prints whatever comes back. `bash`, `zsh`, and `PowerShell` are all shells -
different programs that do this same job with slightly different syntax.

📝 **Terminology.** The words people muddle together:
- **Terminal** - the window that displays text and takes keystrokes (e.g. Terminal.app, Windows Terminal,
  GNOME Terminal, iTerm2).
- **Shell** - the program *running inside* the terminal that interprets your commands (e.g. `bash`,
  `zsh`, `fish`, `PowerShell`).
- **Console** - historically a physical terminal wired to a computer; today people use it loosely to mean
  "the terminal window." Treat it as a casual synonym for terminal.
- **Command line** / **CLI** (command-line interface) - the general *style* of using a computer by typing
  text commands, as opposed to clicking a GUI (graphical user interface).

The clean one-sentence version: **the terminal is the window; the shell is the program in it that reads
your commands.** Hold onto that - it explains everything else in this phase.

**Why this distinction matters.** When someone says "which shell are you using?" they're not asking about
your window; they're asking whether your commands get interpreted by bash, zsh, or PowerShell, because the
syntax differs. When your prompt looks different from a tutorial's, it's usually because you're in a
different *shell*, not a different *terminal*.

## The prompt: the shell telling you it's your turn

When the shell is ready for a command, it prints a **prompt** and waits. That's what the `$` (or `%`, or
`>`, or `PS C:\>`) at the start of the line is - not part of any command, but the shell's way of saying
"I'm listening; type something."

```console
ada@laptop:~$
```
*What just happened:* nothing ran yet - this is the shell *waiting*. Reading it left to right: `ada` is
your username, `laptop` is the machine's name, `~` is where you currently are (`~` means your home folder),
and `$` marks the end of the prompt. Everything you type goes *after* that `$`. Different shells dress this
up differently - zsh on a Mac often ends in `%`, PowerShell shows something like `PS C:\Users\ada>` - but
they all mean "ready for your next command."

⚠️ **Gotcha.** In guides and docs, commands are shown with a leading `$ ` (or `% `, or `> `) to signal
"this is a shell command." **Don't type that leading prompt character.** If a guide shows `$ ls`, you
type `ls` and press Enter. Pasting the `$` in is one of the most common first-day stumbles, and it gives a
baffling `command not found` error.

## The loop: read, evaluate, print, repeat

Here's the rhythm the shell runs in, forever. Every command you ever type goes through the same four
steps:

```mermaid
flowchart LR
  Read[READ<br/>read the line you typed] --> Eval[EVALUATE<br/>ask the OS to run it]
  Eval --> Print[PRINT<br/>show the result or error]
  Print --> Loop[LOOP<br/>fresh prompt, wait]
  Loop --> Read
```

This cycle has a name: the **read-eval-print loop**, or **REPL**. It's not jargon you need to wield, but
it's the whole shape of using a shell: you type a line, it acts, it shows you what happened, it asks for
the next line. Calm and turn-based. You're never in a race; the shell waits as long as you like.

Let's watch one full turn of the loop:

```console
ada@laptop:~$ whoami
ada
ada@laptop:~$
```
*What just happened:* you typed `whoami` and pressed Enter (**read**). The shell recognized it as a program
and asked the OS to run it (**evaluate**). That program printed your username, `ada` (**print**). Then the
shell drew a fresh prompt and went back to waiting (**loop**). One command, one answer, back to ready.

💡 **Key point.** The shell isn't doing the work itself - it's a *middleman*. It reads your request and
hands it to the operating system, which actually runs the program and touches the hardware. (Full picture:
[/guides/what-an-operating-system-is](/guides/what-an-operating-system-is).) The shell's job is to
translate "what you typed" into "what the OS should do."

## Why type at all, when you could click?

It's a fair question. The desktop with its icons and buttons works fine for a lot of things. So why do
developers live in this text window? Three real reasons, worth understanding because they tell you *when*
the terminal is the right tool:

- **Precision.** A command says *exactly* what you want, with no ambiguity. "Delete every file ending in
  `.tmp` in this folder" is one precise line. Doing that by hand in a file browser means hunting,
  eyeballing, and hoping you didn't miss one - a double-edged sword we'll respect carefully in Phase 2.
- **Repeatability and automation.** A command is text. Text can be saved, shared, and rerun. You can hand a
  colleague the exact line you ran, paste it into instructions, or drop it into a script that runs a
  hundred commands while you get coffee. You can't email someone a sequence of mouse clicks.
- **Reach - including remote machines.** Servers in a data center usually have *no desktop at all*. The
  only way to drive them is by typing commands over a network connection. The same skills you're learning
  here are exactly how you'll operate a machine you'll never physically see.

The terminal isn't more powerful because it's harder. It's more powerful because text is precise, saveable,
and works everywhere - even where there's nothing to click.

## Recap

1. The **terminal** is the *window* (it draws text and captures keystrokes); the **shell** is the
   *program inside it* (it reads and runs your commands). They're two different things.
2. `bash`, `zsh`, and `PowerShell` are **shells** - same job, different syntax.
3. The **prompt** (`$`, `%`, `>`, `PS C:\>`) is the shell saying "ready" - don't type it.
4. The shell runs a **read-eval-print loop**: read your line, evaluate it via the OS, print the result,
   loop. Calm and turn-based.
5. We type instead of click for **precision, repeatability, and reach** - including machines that have no
   screen at all.

Now that you know what the window and the shell *are*, let's give your hands something to do: the everyday
commands you'll actually reach for.


---

# The Essential Commands

You know what the shell is and how its loop works. Now let's fill your hands. There are thousands of
commands out there, but the truth is you'll reach for the same small handful constantly - looking around,
moving between folders, reading files, and making/copying/moving/deleting things. Learn these nine well
and you can navigate any system with confidence.

Type along in your own terminal. Doing it once teaches more than reading it five times.

> The transcripts below show a Mac/Linux shell (bash or zsh). PowerShell on Windows has built-in
> equivalents and even understands many of these names as aliases (`ls`, `cd`, `cat` work there too).
> Where it differs in a way that matters, it's noted.

## The anatomy of a command

Almost every command you'll ever type follows the same three-part shape. See it once and every command
afterward is readable:

```text
   ls   -l   Documents
   │    │     │
   │    │     └── ARGUMENT  - what to act on (here: a folder)
   │    └──────── OPTION/FLAG - how to do it (here: "-l" = long, detailed listing)
   └───────────── COMMAND  - the program to run (here: "ls", "list")
```

- The **command** is the name of the program to run - always first.
- **Options** (also called **flags**) change *how* it runs. They usually start with a dash: a single dash
  for short forms (`-l`, `-a`), two dashes for long, readable forms (`--all`, `--help`). They're optional;
  the command has sensible defaults without them.
- **Arguments** are *what* the command acts on - a filename, a folder, some text.

Parts are separated by spaces. That one fact - **spaces separate the pieces** - is behind a gotcha we'll
hit with filenames shortly, so keep it in mind.

📝 **Terminology.** "Option" and "flag" mean the same thing - a setting like `-l` that tweaks a command's
behavior. People use both words interchangeably; don't let the two names fool you into thinking they're
different.

💡 **Key point.** Almost any command accepts `--help` (or `-h`), which prints a summary of its options
and arguments. When you forget how something works, `ls --help` is faster and safer than guessing.

## `pwd` - where am I right now?

The shell is always "standing inside" exactly one folder, called your **current working directory**.
Everything you do happens relative to it, so the first question is always *where am I?*

```console
ada@laptop:~$ pwd
/home/ada
```
*What just happened:* `pwd` ("print working directory") reported the full path of the folder you're
currently in: `/home/ada`. That `/home/ada` is the same place the prompt's `~` was standing in for - `~`
is just shorthand for your home folder. Whenever you feel lost, `pwd` re-orients you. It only reports; it
changes nothing.

## `ls` - what's in here?

```console
ada@laptop:~$ ls
Desktop  Documents  Downloads  notes.txt  photo.jpg
```
*What just happened:* `ls` ("list") showed the contents of your current folder - three folders and two
files. By default it gives you the bare names. Ask for more detail with `-l`:

```console
ada@laptop:~$ ls -l
total 20
drwxr-xr-x  2 ada  ada  4096 Jun 18 09:14 Desktop
drwxr-xr-x  5 ada  ada  4096 Jun 19 11:02 Documents
drwxr-xr-x  3 ada  ada  4096 Jun 17 16:30 Downloads
-rw-r--r--  1 ada  ada   132 Jun 19 10:45 notes.txt
-rw-r--r--  1 ada  ada  8841 Jun 15 13:20 photo.jpg
```
*What just happened:* The `-l` flag switched `ls` into a "long," detailed listing - one item per line with
its permissions, owner, size in bytes, and last-modified date. The leading `d` (as on `Desktop`) marks a
**d**irectory; a leading `-` marks a regular file. You don't need to decode every column today; the point
is that the *same command* gives you the answer at the level of detail you ask for.

⚠️ **Gotcha.** By default `ls` hides files whose names start with a dot (like `.git` or `.bashrc`) - these
"dotfiles" are config files meant to stay out of the way. If a file seems missing, try `ls -a` ("all") to
reveal the hidden ones. They were always there; `ls` was just being tidy.

## `cd` - move to another folder

```console
ada@laptop:~$ cd Documents
ada@laptop:~/Documents$ pwd
/home/ada/Documents
```
*What just happened:* `cd Documents` ("change directory") moved you *into* the `Documents` folder. Notice
the prompt updated - `~` became `~/Documents` - and `pwd` confirms you're now at `/home/ada/Documents`.
Your shell is now standing in a different room, so `ls` and everything else will act there.

A few `cd` moves worth memorizing, because you'll use them constantly:

```console
ada@laptop:~/Documents$ cd ..
ada@laptop:~$ cd
ada@laptop:~$
```
*What just happened:* `cd ..` went *up* one level - `..` always means "the parent folder," so you went
from `Documents` back to `/home/ada`. Then plain `cd` with nothing after it jumped you straight back to
your home folder from wherever you were. (`cd -` is a handy third: it returns you to the folder you were
in just before - like a "back" button.)

📝 **Terminology.** A **path** is the address of a file or folder. `Documents` is a *relative* path
(relative to where you are now); `/home/ada/Documents` is an *absolute* path (the full address from the
top). `.` means "here," `..` means "one level up," and `~` means "my home folder." If paths in general
feel shaky, the sibling guide
[/guides/the-filesystem-explained](/guides/the-filesystem-explained) is the deep dive.

## `cat` - dump a file's contents to the screen

```console
ada@laptop:~$ cat notes.txt
Buy milk
Call the dentist
Finish the terminal guide
```
*What just happened:* `cat` printed the entire contents of `notes.txt` straight into your terminal. It's
the fastest way to glance at a short file without opening an editor. (The odd name is short for
"concatenate" - its original job was joining files together - but day to day you'll use it to peek at
one.)

⚠️ **Gotcha.** `cat` dumps the *whole* file at once. On a short file that's perfect; on a 10,000-line log
it floods your screen and scrolls everything useful off the top. For anything long, use `less` instead.

## `less` - read a long file calmly, one screen at a time

```console
ada@laptop:~$ less server.log
2026-06-19 11:02:14  INFO  server started on port 3000
2026-06-19 11:02:15  INFO  connected to database
2026-06-19 11:03:01  WARN  slow query (1.2s)
...
:
```
*What just happened:* `less` opened the file in a scrollable viewer instead of dumping it. That `:` at the
bottom is `less` waiting for you - it has taken over the screen. Use the **arrow keys** or **Space** to
scroll, type `/word` then Enter to search for "word," and press **`q`** to quit back to your prompt.

⚠️ **Gotcha.** The first time `less` (or a similar pager) takes over your screen, it's easy to feel
trapped - none of your normal commands seem to work, because `less` is intercepting your keys. The way out
is always the same: press **`q`**. Plain `git log`, `man`, and other commands open pagers too; `q` quits
all of them.

## `mkdir` - make a new folder

```console
ada@laptop:~$ mkdir projects
ada@laptop:~$ ls
Desktop  Documents  Downloads  notes.txt  photo.jpg  projects
```
*What just happened:* `mkdir projects` ("make directory") created a new, empty folder named `projects`,
and the follow-up `ls` confirms it's there. Nothing is inside it yet - it's an empty room ready for you to
`cd` into and start working.

## `cp` - copy a file (the original stays put)

```console
ada@laptop:~$ cp notes.txt notes-backup.txt
ada@laptop:~$ ls
Desktop  Documents  Downloads  notes-backup.txt  notes.txt  photo.jpg  projects
```
*What just happened:* `cp` ("copy") made a duplicate of `notes.txt` named `notes-backup.txt`. The shape is
always `cp <source> <destination>` - *from* first, *to* second. The original `notes.txt` is untouched; you
now have two files. (To copy a whole folder and everything inside it, you need `cp -r` - the `-r` flag
means "recursive," i.e. include the contents.)

## `mv` - move or rename (the original does *not* stay)

```console
ada@laptop:~$ mv notes-backup.txt projects/
ada@laptop:~$ ls projects
notes-backup.txt
```
*What just happened:* `mv` ("move") relocated `notes-backup.txt` into the `projects` folder - it's now
*there* and no longer in the home folder. Same `<source> <destination>` shape as `cp`, but `mv` doesn't
leave a copy behind.

Here's the part that surprises people: **renaming and moving are the same operation.** "Move this file to
a new name in the same folder" *is* a rename:

```console
ada@laptop:~$ mv notes.txt todo.txt
ada@laptop:~$ ls
Desktop  Documents  Downloads  photo.jpg  projects  todo.txt
```
*What just happened:* Giving `mv` a destination that's just a different *name* in the same folder renamed
`notes.txt` to `todo.txt`. There is no separate "rename" command in the shell - `mv` is it. That feels odd
at first, then perfectly natural.

## `rm` - delete a file (and this one needs your full attention)

```console
ada@laptop:~$ rm todo.txt
ada@laptop:~$ ls
Desktop  Documents  Downloads  photo.jpg  projects
```
*What just happened:* `rm` ("remove") deleted `todo.txt`. Notice what *didn't* happen: no confirmation
prompt, no "are you sure?", and the command printed nothing at all. Silence means it worked. `todo.txt` is
gone, and the only sign is that it's no longer in the `ls` output.

⚠️ **Gotcha - read this twice.** `rm` does **not** move files to a Recycle Bin or Trash. There is **no
undo**. When you `rm` something, the shell asks the OS to delete it immediately and permanently - it does
not pass through any safety net the desktop gives you. This is the precision from Phase 1 cutting the other
way: the terminal does *exactly* what you said, instantly. Treat `rm` with respect:
- Run `ls` first to confirm you're deleting what you think you are.
- Be extremely careful with `rm -r` (recursive - deletes a folder *and everything inside it*). It's
  powerful and unforgiving.
- If you want a confirmation prompt, `rm -i` asks before each delete. A good habit while you're new.

🪖 **War story.** Every seasoned developer has, at least once, deleted the wrong thing with `rm` and felt
that specific cold drop in the stomach. It's a rite of passage precisely *because* there's no undo. The
fix isn't fear - it's the habit above: look before you delete.

## The gotcha that spans all of these: spaces in filenames

Remember from the anatomy section that **spaces separate the pieces of a command**. So what happens when a
filename itself contains a space?

```console
ada@laptop:~$ cat my notes.txt
cat: my: No such file or directory
cat: notes.txt: No such file or directory
```
*What just happened:* You meant *one* file called `my notes.txt`, but the shell saw the space and split it
into *two* arguments - `my` and `notes.txt` - and went looking for two separate files that don't exist.
The shell isn't being difficult; it genuinely can't tell your filename-space from a separator-space unless
you tell it.

The fix is to **quote** the name, which tells the shell "treat all of this as one piece":

```console
ada@laptop:~$ cat "my notes.txt"
Remember to quote filenames with spaces.
```
*What just happened:* The quotes wrapped `my notes.txt` into a single argument, so `cat` got the one file
you meant and printed it. Single quotes work too. This is why filenames with spaces are a small headache
in the terminal - and why many developers name files `my-notes.txt` or `my_notes.txt` to sidestep it
entirely.

## Recap

1. **Anatomy:** `command [options] [arguments]`, separated by spaces. Options (flags) tweak *how*;
   arguments say *what*. `--help` reminds you of both.
2. **`pwd`** - where am I? **`ls`** (`-l` detailed, `-a` shows hidden) - what's here?
3. **`cd <folder>`** - move in; **`cd ..`** up; **`cd`** home; **`cd -`** back.
4. **`cat`** - dump a short file; **`less`** - scroll a long one (press **`q`** to quit).
5. **`mkdir`** - make a folder. **`cp <from> <to>`** - copy (original stays). **`mv <from> <to>`** - move
   *or* rename (original doesn't stay).
6. **`rm`** - delete, **permanently, no undo, no Recycle Bin**. Look before you leap; `rm -r` deletes whole
   folders.
7. **Quote filenames with spaces** (`"my notes.txt"`), because spaces normally separate command pieces.

You can now navigate and manage files by hand. Next, the features that make the terminal genuinely
*powerful* - chaining commands together and letting the shell do the tedious parts for you.

## Try it yourself

Here's a real (but fake) shell - nothing leaves your browser. Try `ls`, `cd projects`, `cat readme.txt`, `mkdir demo`, then `tree`:

```playground-terminal
```


---

# The Real Power: Pipes, Redirection, Wildcards & PATH

So far each command has stood alone: type one, get its answer, type the next. That's already useful. But
the reason experienced developers genuinely *prefer* the terminal isn't the individual commands - it's that
the shell lets you **wire them together**, **capture their output**, and **act on whole groups of files at
once**, all from one line. This phase is where "I can use the terminal" turns into "the terminal makes me
fast."

The four ideas here - pipes, redirection, wildcards, and PATH - are the ones worth real understanding.
Each is small. Together they're most of what makes a shell powerful.

> The syntax below is bash/zsh (Mac/Linux). PowerShell shares all four *ideas* - it has pipes,
> redirection, wildcards, and a PATH - but pipes something richer than plain text, and a few symbols
> differ. Where it matters, it's flagged. Learn the concepts here and the PowerShell versions read easily.

## Pipes (`|`) - feed one command's output into the next

**What it actually is.** A **pipe**, written `|`, takes the text output of the command on its left and
hands it straight to the command on its right *as that command's input*. Instead of one command printing
to your screen, its output flows into another command for further processing.

**Why this is the big one.** Each shell command is small and does one job. Pipes let you snap them together
like LEGO into a custom tool you invented on the spot. The classic example pairs `ls` (which lists files)
with `grep` (which filters lines, keeping only those that match):

```console
ada@laptop:~/projects$ ls
notes.txt  report-2025.pdf  report-2026.pdf  photo.jpg  draft.md
ada@laptop:~/projects$ ls | grep report
report-2025.pdf
report-2026.pdf
```
*What just happened:* `ls` produced its usual list of filenames - but the `|` meant that list never hit
your screen. Instead it flowed into `grep report`, which kept only the lines containing "report" and
printed those. You just built a "list only the report files" tool out of two general commands. Read the
`|` as the word "then": *list the files, **then** keep the ones matching "report."*

📝 **Terminology.** **`grep`** is a filter: it reads lines of text and prints only the ones matching a
pattern you give it. It's one of the most-used commands in any pipe, precisely because so often you want
"only the lines that mention X."

You can chain more than two. Each `|` passes its left side's output rightward:

```console
ada@laptop:~/projects$ ls | grep report | wc -l
2
```
*What just happened:* `ls` listed the files, `grep report` narrowed to the two report files, and `wc -l`
("word count, lines") counted the lines it received - answering "how many report files are there?" with
`2`. No single command does "count the report files," but three small ones piped together do. That's the
whole spirit of the shell.

## Redirection (`>` and `>>`) - capture output into a file

**What it actually is.** Where a pipe sends output to another *command*, **redirection** sends it to a
*file*. `>` writes the output to a file, and `>>` appends it to the end of a file.

```console
ada@laptop:~/projects$ ls > filelist.txt
ada@laptop:~/projects$ cat filelist.txt
notes.txt
report-2025.pdf
report-2026.pdf
photo.jpg
draft.md
filelist.txt
```
*What just happened:* `ls > filelist.txt` ran `ls`, but instead of printing the list to the screen, `>`
redirected it into a new file called `filelist.txt`. Then `cat` showed that the file now holds exactly
what `ls` would have printed. You've captured a command's output as a file you can keep, edit, or send to
someone.

⚠️ **Gotcha.** A single `>` **overwrites** the target file completely - if `filelist.txt` already had
contents, they're gone, no warning. Use `>>` when you want to *add to* a file instead of replacing it:

```console
ada@laptop:~/projects$ echo "draft.md" >> filelist.txt
ada@laptop:~/projects$ tail -n 1 filelist.txt
draft.md
```
*What just happened:* `>>` appended the line `draft.md` to the *end* of `filelist.txt` without disturbing
what was already there; `tail -n 1` (show the last 1 line) confirms it landed at the bottom. The rule to
burn in: **`>` replaces, `>>` adds.** Reach for `>>` whenever you're not sure, because it's the one that
can't silently erase your file.

And of course pipes and redirection combine - filter, then save the result:

```console
ada@laptop:~/projects$ ls | grep report > reports.txt
ada@laptop:~/projects$ cat reports.txt
report-2025.pdf
report-2026.pdf
```
*What just happened:* `ls` listed files, `grep report` kept the report lines, and `>` wrote that filtered
result into `reports.txt` - a real one-liner that lists, filters, and saves in a single pass. This is the
kind of thing that's clumsy with a mouse and trivial by typing.

## Wildcards (`*`) - act on a whole group of files at once

**What it actually is.** A **wildcard** is a placeholder that matches multiple filenames. The star `*`
means "any run of characters," so `*.pdf` means "every name ending in `.pdf`." This is called **globbing**.

The crucial thing to understand - and the source of a classic surprise - is *who* expands it: the **shell
does the matching before the command ever runs.** The command never sees the `*`; it sees the actual list
of files the shell found.

```console
ada@laptop:~/projects$ ls *.pdf
report-2025.pdf  report-2026.pdf
```
*What just happened:* Before running `ls`, the shell looked in the folder, found every name ending in
`.pdf`, and replaced `*.pdf` with that list. So `ls` actually received `report-2025.pdf report-2026.pdf`
and listed them. The `*` saved you from typing both names - and it would scale identically to fifty PDFs.

It works with any command, which is where it gets powerful (and a little dangerous):

```console
ada@laptop:~/projects$ mkdir pdfs
ada@laptop:~/projects$ mv *.pdf pdfs/
ada@laptop:~/projects$ ls pdfs
report-2025.pdf  report-2026.pdf
```
*What just happened:* The shell expanded `*.pdf` to both PDF filenames, so `mv` received "move these two
files into `pdfs/`" and did exactly that - moving a whole category of files in one line.

⚠️ **Gotcha.** Because the shell expands `*` *before* the command runs, a wildcard with `rm` is genuinely
dangerous - and remember from Phase 2 that `rm` has no undo. `rm *.tmp` deletes every `.tmp` file, fine.
But a stray space turns `rm *.tmp` into `rm * .tmp` - which means `rm *` (delete *everything in the
folder*) followed by `.tmp`. To stay safe, **preview the match with `ls` first**: run `ls *.tmp`, confirm
the list is what you expect, *then* swap `ls` for `rm`. Seeing what `*` matches before you act on it is the
whole safety habit.

## PATH - how the shell finds the program behind a command name

Here's a question you may not have thought to ask: when you type `ls`, how does the shell know *where the
`ls` program actually lives* on disk? `ls` is itself a small program in a file somewhere - so how does
typing five letters find it?

**What it actually is.** **PATH** is a list of folders the shell searches, in order, whenever you type a
command name. When you type `ls`, the shell walks through those folders one by one until it finds a program
called `ls`, and runs the first match. That's the entire mechanism behind every command name you type.

You can see your own PATH. It's stored in an **environment variable** - a named value the shell keeps
around - and `echo` prints it (the `$` tells the shell "give me the *value* of this variable"):

```console
ada@laptop:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/home/ada/.local/bin
```
*What just happened:* `echo $PATH` printed your PATH - a list of folders separated by colons. When you
type any command, the shell searches these folders left to right. `ls` lives in `/bin`, so it's found
there. The leftmost folders win ties, which is why order matters.

📝 **Terminology.** An **environment variable** is a named setting the shell (and the programs it runs)
can read - `PATH` is the most important one. `$NAME` means "the value stored in `NAME`." (On PowerShell
the same idea is written `$env:PATH`, and the folders are separated by semicolons, not colons.)

**Why this saves you later.** That dreaded message -

```console
ada@laptop:~$ myprogram
bash: myprogram: command not found
```
*What just happened:* The shell searched every folder in your PATH, found nothing named `myprogram`, and
gave up. `command not found` almost never means the program is broken - it means **the shell couldn't find
it in any PATH folder.** Either it isn't installed, or it's installed somewhere that isn't on your PATH.
This is *the* single most common terminal error, and now you know precisely what it's telling you: "I
looked in all my folders and there's no program by that name." The fix is to install the program, or to
add its folder to PATH - which is exactly what an installer's "add to PATH" checkbox is doing for you.

💡 **Key point.** A command name is not magic - it's a filename the shell *looks up* in your PATH folders.
Understanding that turns `command not found` from a mystery into a checklist: is it installed, and is its
folder on the PATH?

## The same ideas in PowerShell

You'll meet Windows machines, so it's worth knowing the concepts here are universal even though the syntax
shifts:

- **Pipes** exist (`|`) - but PowerShell pipes *objects* with named fields, not just lines of text, so its
  filtering reads like `Get-ChildItem | Where-Object Name -like "*report*"` rather than `ls | grep`.
- **Redirection** `>` and `>>` work the same way (write / append to a file).
- **Wildcards** `*` work the same way for matching filenames.
- **PATH** exists; you read it with `$env:PATH`, and its folders are separated by `;` instead of `:`.

Different words, identical ideas. Once you hold the concepts, you can read either shell.

## Recap

1. **Pipe `|`** - sends one command's output into the next as input. Read it as "then." `ls | grep report`
   = "list, then keep the report ones." Chain freely.
2. **Redirect `>` / `>>`** - sends output to a *file*. `>` **overwrites**; `>>` **appends**. When unsure,
   use `>>`.
3. **Wildcard `*`** - matches groups of filenames; the **shell expands it before the command runs**.
   Preview a match with `ls` before using it with `rm`.
4. **PATH** - the list of folders the shell searches to find the program behind a command name. `echo
   $PATH` shows it; `command not found` means it wasn't found in any of them.
5. The concepts carry to **PowerShell** even though some syntax differs.

That's the whole foundation. You know what the terminal and shell *are*, the everyday commands to drive
them, and the power features that let you combine, capture, and scale your work. From here, the natural
next step is **shell scripting** - saving a sequence of these commands in a file so you can rerun your own
little tools on demand. But everything a script does, you can now do by hand, on purpose, knowing exactly
what each line means.
