Section 01

Understanding the Basics

Before typing commands, understand what you're actually talking to.

🖥 What is a Terminal?

A terminal (or terminal emulator) is simply the window application you open to type commands. On macOS it's called Terminal.app or you might use iTerm2. On Windows it's Windows Terminal or PowerShell. On Linux it's GNOME Terminal, Konsole, etc.

Think of it like a text message app -- it's just the interface. The terminal itself doesn't understand your commands. It passes them to something called a shell.

🐚 What is a Shell?

A shell is the interpreter that actually reads and executes your commands. When you type ls, the shell figures out what that means and runs it.

Common shells include Bash (Bourne Again SHell), Zsh (Z Shell), Fish, and sh. They each have slightly different syntax and features, but they all do the same fundamental job: interpret your typed commands.

What is a Kernel?

The kernel is the core of your operating system. It's the software that directly talks to your hardware -- CPU, memory, disk, network cards, etc.

When your shell runs a command like "read this file," it asks the kernel. The kernel is the middleman between software and hardware. You never interact with it directly -- the shell does that for you.

📊 How They All Relate

Every command you type flows through these layers:

You (the human)
Type commands with your keyboard
sends keystrokes to
Terminal
The window app (iTerm2, Terminal.app)
passes input to
Shell (Bash / Zsh)
Interprets commands, runs programs
makes system calls to
Kernel (Linux / Darwin)
Manages resources, talks to hardware
controls
Hardware
CPU, RAM, Disk, Network, GPU
🔄 Bash vs Zsh

Since macOS Catalina (2019), the default shell is Zsh. Before that, it was Bash. Linux mostly defaults to Bash.

The good news: they're ~95% the same. Almost every command, pipe, redirect, and script works identically in both. Zsh adds fancier tab-completion, themes (Oh My Zsh), and some syntax sugar. If you learn Bash, you effectively know Zsh too.

💡 Check your current shell: run echo $SHELL. You'll see /bin/zsh or /bin/bash.
📖 What is PATH?

PATH is an environment variable that tells your shell where to look for programs.

Analogy: Imagine your phone's contact list. When you say "call Mom," your phone looks through your contacts to find the number. PATH works the same way -- when you type git, the shell searches through a list of directories (the PATH) to find the git program.

Viewing your PATH
$ echo $PATH
Output
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Each directory is separated by :. The shell checks them left to right until it finds the program.

📡 stdin, stdout, stderr

Every program has three standard streams -- think of them as three channels for data:

fd 0 stdin
your Program
fd 1 stdout
fd 2 stderr

stdin (standard input) -- data going INTO a program (keyboard input, or piped data).

stdout (standard output) -- normal output from a program (what you see printed).

stderr (standard error) -- error messages. Looks the same as stdout on screen, but it's a separate channel so you can handle errors differently.

Redirecting stderr separately
$ ls /real-dir /fake-dir 2> errors.txt
What happens
stdout (list of /real-dir) prints to screen stderr ("No such file" for /fake-dir) goes into errors.txt
🔧 Pipes and Redirection

These operators let you connect programs and control where data flows:

| Pipe -- sends stdout of one command as stdin to the next. cat file.txt | grep "error" > Redirect stdout -- write output to a file (overwrites). echo "hello" > file.txt >> Append stdout -- add output to end of file. echo "world" >> file.txt < Redirect stdin -- use a file as input. sort < names.txt 2> Redirect stderr -- send errors to a file. cmd 2> errors.log &> Redirect all -- send both stdout and stderr. cmd &> output.log
Chaining pipes
$ cat access.log | grep "404" | sort | uniq -c | sort -rn | head -5
What this does
Read log → find 404 errors → sort them → count unique lines → sort by count → show top 5
📝 .zshrc — Your Shell's Memory

Every time you open a new terminal window, your shell starts fresh — it has no memory of what you did before. So how does it remember your preferences, custom commands, and PATH changes? That's what .zshrc is for.

What is .zshrc?

The .zshrc file (short for "zsh run commands") is a script that runs automatically every time you open a new terminal. It lives in your home directory at ~/.zshrc. Think of it as your shell's startup checklist — everything in this file gets executed before you even see the prompt.

💡
The dot (.) at the beginning makes it a hidden file. You won't see it in Finder, but it's always there. Use ls -a ~ to see hidden files.

How it connects to the Kernel and Shell

Remember the layers from earlier:

Kernel Manages hardware, memory, processes. You never talk to it directly. Shell (zsh) Translates your commands into kernel calls. Needs to be configured each session. .zshrc Configures the shell automatically on every startup, so you don't have to.

Without .zshrc, you'd have to re-type all your preferences every time you open Terminal. The shell reads this file, applies your settings, and then shows you the prompt.

What goes in .zshrc?

~/.zshrc (example)
# PATH — tell the shell where to find programs
export PATH="/opt/homebrew/bin:$PATH"

# Aliases — shortcuts for commands you type often
alias ll="ls -la"
alias gs="git status"
alias gp="git push"

# Environment variables — settings for programs
export EDITOR="code"
export ANTHROPIC_API_KEY="sk-ant-..."

# Oh My Zsh — loads plugins and themes
source ~/.oh-my-zsh/oh-my-zsh.sh

# NVM — Node version manager setup
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"

Common .zshrc tasks

export PATH="..." Add directories so the shell can find new programs (Homebrew, Node, Python) alias name="cmd" Create shortcuts — type gs instead of git status export VAR="val" Set environment variables that programs read (API keys, editor prefs) source file.sh Run another script's commands — used by Oh My Zsh, NVM, etc.

Editing and reloading

Terminal
$ code ~/.zshrc # open in VS Code/Cursor

After editing, reload without closing the terminal:

Terminal
$ source ~/.zshrc
⚠️
Be careful: If you break the syntax in .zshrc, every new terminal will show errors. If this happens, you can always fix it by editing the file directly: nano ~/.zshrc

Other config files

You might also encounter these related files:

.zprofile Runs once at login (not every new tab). Good for one-time setup. .zshenv Runs for every zsh instance, even scripts. Rarely edited directly. .bashrc Same concept but for Bash (the older default shell). macOS switched to zsh in 2019.
Section 02

Interactive Bash Guide

Walk through essential commands with examples and expected output.

🧭 Navigation
Where am I? Moving around
$pwd
Output
/Users/yourname
pwd = "Print Working Directory." Shows the full path of where you currently are in the filesystem. Think of it as asking "what folder am I in right now?"
List files
$ls
Output
Desktop Documents Downloads file.txt notes.md
List with details
$ls -la
Output
total 24 drwxr-xr-x 6 user staff 192 Apr 3 10:00 . drwxr-xr-x 5 user staff 160 Apr 1 09:00 .. -rw-r--r-- 1 user staff 420 Apr 3 09:30 file.txt drwxr-xr-x 3 user staff 96 Apr 2 14:00 Desktop -rw-r--r-- 1 user staff 128 Apr 1 08:00 .hidden-file
-l = long format (permissions, owner, size, date). -a = show ALL files, including hidden ones (those starting with a dot). Together -la gives you the complete picture of what's in a directory.
Changing directories
$cd Documents
$cd ..
$cd ~
$cd -
What each does
cd Documents → go into Documents folder cd .. → go up one level (parent directory) cd ~ → go to your home directory cd - → go back to previous directory (like "undo")
📁 File Operations
Creating files and directories
$touch newfile.txt
$mkdir my-project
$mkdir -p deep/nested/directory
What each does
touch → create an empty file (or update its timestamp) mkdir → create a directory mkdir -p → create nested dirs (makes parents if they don't exist)
Copy, move, remove
$cp file.txt backup.txt
$cp -r folder/ folder-backup/
$mv old-name.txt new-name.txt
$rm unwanted-file.txt
$rm -rf old-directory/
rm -rf deletes recursively and forcefully with no confirmation and no trash can. There is no undo. Always double-check your path before running this.
Reading files
$cat file.txt
$head -5 file.txt
$tail -10 file.txt
$less file.txt
What each does
cat → print entire file to screen head → show first N lines tail → show last N lines less → paginated viewer (q to quit, / to search)
🔍 Search & Find
Finding files and text
$find . -name "*.js"
$find /var/log -type f -mtime -1
$grep "error" logfile.txt
$grep -r "TODO" ./src/
$grep -rn "function" --include="*.js" .
What each does
find . -name "*.js" → find all .js files in current dir find /var/log -type f -mtime -1 → files modified in last 24h grep "error" logfile.txt → search for "error" in a file grep -r "TODO" ./src/ → recursive search in directory grep -rn "function" ... → recursive + line numbers + file filter
find searches for files by name, type, size, or date. grep searches for text inside files. Use find when you know the filename pattern, and grep when you know what the file contains.
Locating programs
$which python3
$which git
Output
/usr/bin/python3 /usr/bin/git
🖥 System Information
Who and where
$whoami
$hostname
$uname -a
Output
yourname MacBook-Pro.local Darwin MacBook-Pro 25.4.0 Darwin Kernel Version 25.4.0 ... x86_64
Disk and process info
$df -h
$du -sh ~/Documents
$ps aux | head -10
$top
What each does
df -h → disk free space (human-readable) du -sh ~/Docs → size of a directory ps aux → all running processes top → live process monitor (q to quit)
🔒 Permissions

Every file has permissions for three groups: owner, group, and others.

Reading permissions
$ls -l script.sh
Output
-rwxr-xr-x 1 user staff 256 Apr 3 10:00 script.sh ^^^ ^^^ ^^^ owner group others r = read, w = write, x = execute
Changing permissions
$chmod +x script.sh
$chmod 755 script.sh
$chmod 644 config.txt
$chown user:staff file.txt
What each does
chmod +x → make file executable chmod 755 → rwxr-xr-x (owner: full, others: read+exec) chmod 644 → rw-r--r-- (owner: read+write, others: read only) chown → change file owner and group
Each digit represents a group (owner, group, others). The number is a sum: 4 = read, 2 = write, 1 = execute. So 7 (4+2+1) = rwx, 5 (4+1) = r-x, 6 (4+2) = rw-, 0 = ---. Example: chmod 750 means owner=rwx, group=r-x, others=nothing.
📝 Text Processing
Text tools
$echo "Hello, World!"
$wc -l file.txt
$sort names.txt
$sort names.txt | uniq
$cut -d',' -f1 data.csv
What each does
echo → print text to stdout wc -l → count lines in a file sort → sort lines alphabetically uniq → remove adjacent duplicate lines (sort first!) cut → extract columns (-d = delimiter, -f = field)
sed and awk basics
$sed 's/old/new/g' file.txt
$sed -i '' 's/foo/bar/g' file.txt
$awk '{print $1, $3}' data.txt
$awk -F',' '{print $2}' data.csv
What each does
sed 's/old/new/g' → find-and-replace text (g = all occurrences) sed -i '' 's/...' → edit file in-place (macOS syntax) awk '{print $1}' → print 1st column (space-separated) awk -F',' ... → use comma as field separator
sed (stream editor) is best for simple find-and-replace operations on text. awk is a mini programming language designed for processing columnar data. Rule of thumb: use sed to change text, use awk to extract/format columns.
🌐 Networking
Network commands
$curl https://api.github.com
$curl -s https://example.com | head -5
$wget https://example.com/file.zip
$ping -c 3 google.com
$ifconfig | grep "inet "
What each does
curl → make HTTP requests (fetch URLs, APIs) curl -s → silent mode (no progress bar) wget → download files from the web ping → test network connectivity (-c 3 = only 3 pings) ifconfig → show network interfaces and IP addresses
⚙ Process Management
Managing processes
$sleep 100 &
$jobs
$fg %1
$kill 12345
$kill -9 12345
$nohup ./server.sh &
What each does
& → run command in background jobs → list background jobs fg %1 → bring job #1 to foreground kill PID → gracefully stop a process kill -9 → force kill (last resort) nohup → keep running after terminal closes
💡 Press Ctrl+Z to suspend a running process, then bg to resume it in the background, or fg to bring it back.
🌍 Environment Variables
Working with environment variables
$echo $HOME
$export MY_VAR="hello"
$echo $MY_VAR
$env | head -10
$printenv PATH
What each does
$HOME → reference a variable's value export → set a variable available to child processes env → list all environment variables printenv → print a specific variable's value
Shell config files
$cat ~/.zshrc
$source ~/.zshrc
What they are
~/.bashrc → Bash config, runs on every new terminal ~/.zshrc → Zsh config (macOS default) source → reload config without restarting terminal These files are where you put your aliases, PATH additions, and exports.
MY_VAR="hello" sets a variable only for the current shell. export MY_VAR="hello" makes it available to any program launched from that shell (child processes). If you want an app you run to see the variable, you need export.
Section 03

Bash Cheatsheet

Quick reference cards. Click any command to copy it.

🧭 Navigation
pwdPrint current directory
ls -laList all files with details
cd ~Go to home directory
cd ..Go up one level
cd -Go to previous directory
tree -L 2Show directory tree (2 levels)
📁 File Operations
touch file.txtCreate empty file
mkdir -p dir/subCreate nested directories
cp -r src/ dst/Copy directory recursively
mv old newMove or rename
rm -rf dir/Delete recursively (careful!)
cat file.txtPrint file contents
🔍 Search & Find
find . -name "*.txt"Find files by name
grep -rn "text" .Search text recursively
grep -i "pattern" fileCase-insensitive search
which commandShow command location
find . -type f -mtime -1Files modified today
find . -size +100MFiles larger than 100MB
🔒 Permissions
chmod +x script.shMake executable
chmod 755 filerwxr-xr-x
chmod 644 filerw-r--r--
chown user:group fileChange owner
ls -lView permissions
📝 Text Processing
wc -l file.txtCount lines
sort file.txt | uniq -cCount unique lines
cut -d',' -f1 data.csvExtract first CSV column
sed 's/old/new/g' fileFind and replace
awk '{print $1}' filePrint first column
head -20 file.txtFirst 20 lines
tail -f log.txtFollow log file (live)
🔧 Pipes & Redirection
cmd1 | cmd2Pipe stdout to next command
cmd > file.txtWrite stdout to file
cmd >> file.txtAppend stdout to file
cmd < input.txtUse file as stdin
cmd 2> errors.logRedirect stderr to file
cmd &> all.logRedirect stdout + stderr
cmd1 && cmd2Run cmd2 only if cmd1 succeeds
cmd1 || cmd2Run cmd2 only if cmd1 fails
Process Management
ps auxList all processes
kill PIDGracefully stop a process
kill -9 PIDForce kill a process
jobsList background jobs
bg %1Resume job in background
fg %1Bring job to foreground
nohup cmd &Run surviving terminal close
🌍 Environment Variables
export KEY="val"Set env variable
echo $HOMEPrint variable value
envList all env variables
printenv PATHPrint specific variable
source ~/.zshrcReload shell config
unset MY_VARRemove a variable
Keyboard Shortcuts — Terminal vs iTerm2

Shell shortcuts (Ctrl+) work in both. iTerm2 adds powerful app-level shortcuts (Cmd+).

💻 Terminal & Shell (works in both)

Ctrl+CCancel current command
Ctrl+ZSuspend current process
Ctrl+DExit shell / end input
Ctrl+RReverse search history
Ctrl+LClear screen
TabAuto-complete file/command
Up ArrowPrevious command
Ctrl+AJump to start of line
Ctrl+EJump to end of line
Ctrl+WDelete word before cursor
Ctrl+UDelete entire line

✨ iTerm2 Extras

Cmd+DSplit pane vertically
Cmd+Shift+DSplit pane horizontally
Cmd+]Next pane
Cmd+[Previous pane
Cmd+TNew tab
Cmd+WClose tab/pane
Cmd+FSearch terminal output
Cmd+Shift+HPaste history
Cmd+;Autocomplete from history
Cmd+Option+ESearch across all tabs
Cmd+EnterToggle fullscreen