// linux fundamentals — module 01
Module 1 — The Shell and the Command Line
Thesis: The shell is an ordinary program that reads a line of text, interprets it, runs other programs, and shows their output. Nothing more mystical than that. But it is the tool you'll use to explore every other topic in this course, so fluency here multiplies everything that follows.
Prerequisite: Module 0 — What Linux Even Is — you know the shell is a userland program, not the kernel and not "Linux."
1.1 Terminal vs. shell — two programs, not one
When you "open a terminal," two separate programs start working together, and keeping them straight matters:
- The terminal emulator (Konsole, GNOME Terminal, Alacritty, kitty…) is the window: it draws characters on screen and forwards your keystrokes. It's an emulator of the physical teletype terminals that were wired to Unix machines in the 1970s — which is why the whole interface is lines of text.
- The shell (
bash,zsh,fish…) is the program running inside that window. It prints a prompt, reads the line you type, figures out what you meant, launches programs, and hands their output back to the terminal to draw.
Swap either independently: the same shell runs in any terminal, and a terminal can host any shell. This course uses bash syntax, which zsh (your shell, if you're on a default macOS-like setup or configured NixOS) accepts almost entirely for everything we do.
The prompt — something like kroma@machine ~ $ — is just the shell saying "ready." Convention: a prompt ending in $ means a normal user; # means root (Module 4). When documentation shows $ command, you type only the part after $.
1.2 The anatomy of a command
Every command line has the same shape:
command option(s) argument(s)
ls -l /etc
- The command is (usually) the name of a program to run.
- Arguments are the inputs you hand it — here, the directory to list.
- Options (also called flags or switches) modify behavior. Two styles:
- Short options: a dash and a letter,
-l. Bundleable:ls -la=ls -l -a. - Long options: two dashes and a word,
--all. Readable, unbundleable. - Some options take their own values:
grep --color=auto, ortar -f archive.tar.
- Short options: a dash and a letter,
The shell splits your line into words on spaces before the program ever sees it. This single fact explains half of all beginner surprises: to the shell, rm My Documents is the command rm with two arguments, My and Documents. Handling that correctly is §1.7 (quoting).
There is one wrinkle to know now: a few "commands" (cd, echo, export, and others) are shell builtins — implemented inside the shell itself rather than as separate programs. type cd will tell you cd is a shell builtin; type ls will name a file on disk. Why must cd be a builtin? Hold that question — Module 5 gives you the vocabulary to answer it precisely (a separate program couldn't change the shell's directory). For now: type <name> tells you what kind of thing a command is.
1.3 The filesystem from the shell's point of view
Linux organizes all files into one single tree, rooted at / (called "root" — no relation to the root user yet). There are no drive letters; every disk, USB stick, and network share appears somewhere inside the one tree (how they get there is Module 3's mounting).
A path names a location in the tree:
- An absolute path starts with
/and spells the full route from the root:/home/kroma/notes/todo.md. Unambiguous, always valid, regardless of where you are. - A relative path does not start with
/and is interpreted from your current working directory: if you're in/home/kroma, thennotes/todo.mdmeans the same file.
Every running program — including your shell — has a current working directory. Three commands manage yours:
pwd # print working directory — "where am I?"
cd /etc # change directory (absolute)
cd notes # change directory (relative)
cd # with no argument: jump to your home directory
cd - # jump back to wherever you just were
Special names, valid inside any path:
.— this directory itself..— the parent directory (cd ..= go up one level;../../x= up two, then intox)~— your home directory (/home/yourname), the one part of the tree that belongs to you; expanded by the shell, so~/notes=/home/kroma/notes
And the workhorse, ls (list):
ls # names in the current directory
ls -l # long format: permissions, owner, size, date (you'll read every column by Module 4)
ls -a # include hidden files — any name starting with a dot
ls -lh # long format with human-readable sizes (4.2M, not 4404019)
ls /var/log # list somewhere else without going there
The "dotfile" convention: a file named with a leading dot (like ~/.bashrc) is hidden only in the sense that ls omits it by default. It's a convention for keeping configuration out of the way, not a security feature.
1.4 Making, moving, and destroying things
mkdir projects # make a directory
mkdir -p a/b/c # make nested directories in one go
touch notes.md # create an empty file (or update its timestamp)
cp notes.md backup.md # copy a file
cp -r projects archive # copy a directory (r = recursive: it and everything inside)
mv notes.md ideas.md # rename…
mv ideas.md projects/ # …and move — same command, because both just change a name (Module 3 explains why)
rm backup.md # remove a file
rmdir projects # remove an EMPTY directory
rm -r archive # remove a directory and everything in it
Now the safety briefing, because it's earned: there is no trash can and no undo. rm deletes immediately and permanently. Three habits, starting today:
- Before any
rmwith a wildcard (§1.6), runlswith the same pattern first, and look at what came back. That list is exactly whatrmwill destroy. - Treat
rm -rf(recursive + force, no prompts) as a loaded tool: pause and re-read the line before pressing Enter. - Understand this famous disaster so you never re-create it:
rm -rf ~/tmp /*— note the accidental space before*— asks to delete~/tmpand everything under/. The shell's word-splitting from §1.2 is why that space is fatal: it turned one path into two.
1.5 Reading files and getting help
Everything in Linux is configured and logged in plain text (Module 0's Unix philosophy), so reading text is a primary skill:
cat file # print the whole file to the terminal — fine for short files
less file # page through a long file interactively
head file # first 10 lines (-n 25 for 25)
tail file # last 10 lines
tail -f file # follow: keep printing lines as they're appended — perfect for watching logs live
wc -l file # count lines
grep pattern file # print only lines containing pattern — preview of a lifelong friendship
Learn less properly — it's also what displays man pages, so these keys pay double: Space/b page down/up, j/k line down/up, g/G jump to start/end, /text search forward, n/N next/previous match, q quit.
Getting help, in the order to try it:
man command— the manual page: the authoritative reference, displayed inless. The format: NAME, SYNOPSIS (the usage grammar — brackets mean optional), DESCRIPTION, then every option. Man pages are references, not tutorials; the skill is searching them (/) for the flag you need, not reading them end to end.command --help— a quick usage summary printed by the program itself.tldr command(install it) — community-written examples of common usage; often the fastest answer.apropos keyword— search all man page descriptions when you don't know the command's name:apropos rename.
The manual is split into numbered sections: 1 = user commands, 5 = file formats, 7 = concepts, 8 = admin commands. This matters when a name exists in several: man passwd gives the command, man 5 passwd gives the file format of /etc/passwd (a file you'll dissect in Module 4). The conceptual overviews in section 7 are treasures: man 7 signal, and man 7 hier — the entire filesystem layout, documented, which is Module 3 in your pocket.
1.6 Globbing: patterns for filenames
You'll constantly want "all the .log files" without typing each name. Globs (wildcards) do this:
*— any sequence of characters (including none):*.log,report-*?— exactly one character:file?.txtmatchesfile1.txt, notfile10.txt[...]— one character from a set:[abc]*,file[0-9].txt;[!0-9]negates
The critical mental model: the shell expands the glob, not the program. When you type rm *.log, the shell replaces *.log with the actual matching filenames before running rm — so rm receives a.log b.log c.log and never sees a star. Two consequences:
echo *.logis a perfect safe preview of any glob — it shows you the exact expansion.- If nothing matches, bash passes the pattern through literally, and the program receives the string
*.log— usually producing a "no such file" error that confuses beginners. Now it won't confuse you.
Note the difference from ls's default: globs don't match leading-dot (hidden) files. * in your home directory will not include .bashrc.
1.7 Quoting: controlling the shell's interpretation
You now know the shell transforms your line before running it: splitting on spaces (§1.2), expanding globs (§1.6), and expanding variables (§1.8). Quoting is how you suppress those transformations when you don't want them:
- Double quotes
"…"— protect spaces and globs, but still expand variables:"$HOME dir"becomes/home/kroma dir, as one word. - Single quotes
'…'— protect everything literally:'$HOME dir'stays exactly$HOME dir. - Backslash
\— protect the single next character:My\ Documents.
Rules of thumb that will serve you for years: filenames with spaces need quotes (cd "My Documents"); when in doubt, double-quote variable uses ("$file", not $file — if the value contains a space, the unquoted form splits into two words, and you already know from §1.4 what a surprise extra word can do to an rm).
1.8 The environment and $PATH
Every process carries a set of environment variables — named text values, like a keyring of settings — which it passes down to every program it starts. Your shell's environment is where per-user configuration lives at runtime:
echo $HOME # read one variable (the $ asks the shell to substitute its value)
env # list them all
MYVAR="hello" # set a shell variable (this shell only)
export MYVAR # promote it to the environment: now child programs inherit it
export EDITOR=vim # set and export in one step
Common residents: HOME (your home directory), USER, SHELL, LANG (language/locale), EDITOR (which editor other programs should launch) — and the most important one on the system:
$PATH answers the question: when you type ls, how does the shell find the program? Look at it:
echo $PATH
/home/kroma/.local/bin:/usr/local/bin:/usr/bin:/bin
It's a colon-separated list of directories. The shell checks each, in order, left to right, and runs the first file named ls it finds. That's the whole mechanism. Everything about "installing a program makes a command available" reduces to: a file appeared in a $PATH directory. Related tools:
which ls # which file would run? → /usr/bin/ls
type ls # same question, but also knows about builtins and aliases
Two classic $PATH puzzles you can now solve: "command not found" for a program you installed = its directory isn't on $PATH. "The wrong version runs" = another copy sits earlier on $PATH.
Finally: where do your customizations live? Shells read startup files from your home directory when they launch — ~/.bashrc for bash, ~/.zshrc for zsh. That's where export EDITOR=vim goes to become permanent. (On NixOS you'll eventually generate these files declaratively — but what's in them means the same thing.)
1.9 History and line editing — the wrist-savers
The shell remembers what you've typed, and mastering recall is what makes fast users fast:
- ↑ / ↓ — step through previous commands
Ctrl-R— reverse search: type any fragment of an old command and it finds it; pressCtrl-Ragain for older matches. The single highest-value shortcut in this list.history— the whole list;!!reruns the last command (classic use:sudo !!after a permission error, once you have Module 4)- Tab — completion: type a prefix of any command or path and press Tab; twice to list all options. Tab-completing paths also prevents typos in
rmcommands — let the shell type the dangerous parts. - Line editing:
Ctrl-A/Ctrl-Estart/end of line ·Ctrl-Wdelete word backwards ·Ctrl-Uwipe the line ·Ctrl-Lclear screen Ctrl-CandCtrl-Z— you'll meet these properly in Module 5; they're not "shortcuts" at all, but signals.
1.10 → NixOS
$PATH is the perfect warm-up for Nix's biggest idea. On a conventional distro, thousands of programs share a few directories (/usr/bin had everything in Lab 0). Under Nix, each package lives in its own isolated directory (like /nix/store/abc123…-ripgrep-14.1.0/bin), and your $PATH — or a merged symlink tree it points to — is assembled from exactly the packages your configuration declares. Same lookup mechanism you learned in §1.8, radically different feeding of it. When you later run echo $PATH on NixOS and see strange hashed paths, you'll read them fluently: it's just $PATH, being fed differently.
Lab 1
Work in your home directory. Type everything; use Tab completion constantly.
Build and demolish a small world.
mkdir -p lab1/docs lab1/logs cd lab1 touch docs/a.md docs/b.md logs/app1.log logs/app2.log logs/app10.logNow, from inside
lab1: listdocswithout leaving your current directory; then uselswith a glob to show onlyapp?.loginlogsand explain whyapp10.logis excluded; then previewlogs/*.logwithechobefore deleting those files with the same pattern.Find where a program lives. Run
which ls, thenls -lon the path it printed. Then runtype cdand compare. Explain the difference in one sentence.Read your
$PATHout loud. Runecho $PATHand narrate: "when I type a command, the shell tries this directory first, then this one…" Then predict what happens if the same program name exists in two of them, and say which wins.Prove environment inheritance. Run
export LABVAR=hello, then start a new shell by typingbash(orzsh), andecho $LABVARinside it — inherited. Typeexitto return. Now set one withoutexportand repeat: not inherited. That difference is whatexportmeans.Use the manual for real. Using only
man lsand/searching: find the flag for human-readable sizes, the flag to sort by modification time, and the flag to reverse sort order. Combine all three with-lto answer: what's the oldest file in/etc?Master reverse search. Press
Ctrl-R, typemkdir, and resurrect your command from step 1. Then useCtrl-Ato jump to its start.Spaces, the hard way. Run
touch "two words.txt", then trycat two words.txtand read the error carefully — which two files didcatlook for? Fix it two different ways (quotes; backslash). This error message will now never confuse you again.
✅ Mastery Check — do not proceed until true
Answer out loud, without notes:
- What's the difference between the terminal emulator and the shell?
- Given
ls -lh /var/log, name the command, options, and argument. Who splits the line into those words? - What's the difference between an absolute and a relative path? What do
.,.., and~mean? - When you type
rm *.txt, doesrmsee the*? Explain exactly what happens, and how to safely preview it. - What does
$PATHcontain, and precisely how does the shell use it when you type a command name? Explain how "command not found" and "wrong version runs" both reduce to$PATHfacts. - What's the difference between
'$HOME',"$HOME", and$HOMEunquoted? - What does
exportchange about a variable?
And perform cold, without hesitation:
- Navigate anywhere in the tree, create a nested directory structure, populate, copy, rename, and safely delete it.
- Find any flag of any command using
manand/. - Recall any earlier command with
Ctrl-R.
When all of that is effortless: Module 2 — The Kernel