1. The Linux Filesystem & Permissions
Linux organizes everything — files, devices, even running processes — as a single
tree rooted at /. Unlike Windows, there's no C:\; every
drive and partition gets mounted somewhere inside that one tree. A handful of
top-level directories show up constantly:
/bin, /usr/bin # executables (ls, bash, docker, ...)
/etc # system-wide configuration files
/home/<user> # your personal files and dotfiles
/var # logs, caches, and other data that changes at runtime
/tmp # scratch space, cleared on reboot
You'll live in a handful of navigation and inspection commands:
pwd # print working directory
ls -la # list all files, including hidden dotfiles, in long format
cd /var/log # change directory
cat app.log # print a file's contents
less app.log # page through a large file (q to quit)
find . -name "*.log" # search recursively for files matching a pattern
Every file has an owner, a group, and permission bits for three audiences —
owner, group, and everyone else —
each with read (r), write (w) and execute (x)
flags. ls -la prints them as a ten-character string:
$ ls -la deploy.sh
-rwxr-xr-- 1 ada devops 812 Jan 12 09:14 deploy.sh
# - rwx r-x r--
# type owner group others
# owner (ada): read, write, execute
# group (devops): read, execute
# others: read only
chmod 750 deploy.sh # owner: rwx, group: r-x, others: ---
chmod +x deploy.sh # add execute for everyone
chown ada:devops deploy.sh # change owner and group
sudo chmod 600 id_rsa # only the owner can read/write -- required for SSH keys
The numeric form (750) is three digits, one per audience, where each
digit sums r=4, w=2, x=1. 750
means owner 7 (4+2+1 = rwx), group 5 (4+1 = r-x), others
0 (none). You'll type this pattern constantly once SSH keys and
deployment scripts show up.
Almost every "permission denied" error you'll hit setting up a CI runner, an SSH key, or a Docker volume traces back to this exact owner/group/others model — being able to read a permission string on sight will save you real debugging time later in this course.
2. Processes & Package Managers
A process is a running program. Every process has a numeric ID (PID), a parent process, and a resource footprint you can inspect directly:
ps aux # list every running process
top # live, updating view of CPU/memory usage
kill 4821 # ask process 4821 to terminate gracefully (SIGTERM)
kill -9 4821 # force-terminate it (SIGKILL) -- last resort
You'll rarely install software by downloading a binary by hand. Each major Linux distribution ships a package manager that resolves dependencies, verifies checksums, and tracks what's installed so it can be cleanly removed later:
sudo apt update # refresh the package index
sudo apt install git curl jq # install packages
apt list --installed | grep git
This course uses Ubuntu-based examples throughout, but the pattern is the same
everywhere: Red Hat/Fedora use dnf, Arch uses pacman, and
macOS's unofficial equivalent is brew. Your first real task is getting
the tools this course leans on installed and confirmed working:
sudo apt install -y git curl jq
git --version
curl --version
jq --version
Install WSL2 (wsl --install from an admin PowerShell prompt) and use its Ubuntu shell for every command in this course. It's a real Linux kernel, not an emulator, so everything here — permissions, package managers, Docker — behaves exactly like it would on a Linux server.
3. Bash Scripting Basics
A shell script is just a sequence of the same commands you'd type interactively,
saved to a file so you never have to type them again. Variables, conditionals and
loops turn that into real automation — the same shape you'll later see in CI
pipeline steps and Dockerfile RUN commands.
#!/usr/bin/env bash
set -euo pipefail # exit on error, on unset variables, and on pipe failures
THRESHOLD=80
USAGE=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$USAGE" -ge "$THRESHOLD" ]; then
echo "WARNING: disk usage at ${USAGE}%, threshold is ${THRESHOLD}%"
exit 1
else
echo "OK: disk usage at ${USAGE}%"
fi
set -euo pipefail belongs at the top of nearly every script you'll
write in this course: -e stops the script the moment any command fails,
-u turns a typo'd variable name into an immediate error instead of a
silent empty string, and pipefail makes a failure anywhere in a
cmd1 | cmd2 pipeline fail the whole line, not just the last command.
#!/usr/bin/env bash
set -euo pipefail
LOG_DIR="${1:-/var/log/myapp}" # first argument, defaulting to /var/log/myapp
DEST="/tmp/backups/$(date +%F)"
mkdir -p "$DEST"
for file in "$LOG_DIR"/*.log; do
name=$(basename "$file")
cp "$file" "$DEST/$name"
echo "Backed up: $name"
done
echo "Done. $(ls "$DEST" | wc -l) files copied to $DEST"
Run it with chmod +x backup-logs.sh && ./backup-logs.sh /var/log/nginx.
Quoting variables ("$file", not $file) matters: unquoted,
a filename with a space in it splits into two arguments and silently breaks the
script — one of the most common Bash bugs you'll run into.
4. SSH & Remote Servers
SSH (Secure Shell) is how you'll administer every remote machine in this course — a cloud VM in Week 8, a CI runner, a Kubernetes node. It authenticates with a public/private key pair instead of a password by default:
# Generate a key pair once (press Enter to accept defaults)
ssh-keygen -t ed25519 -C "you@example.com"
# Copy your public key to a remote server you already have password access to
ssh-copy-id ada@203.0.113.10
# Connect -- no password needed after the key is installed
ssh ada@203.0.113.10
# Copy a file to/from a remote host
scp ./deploy.sh ada@203.0.113.10:/home/ada/
The private key (~/.ssh/id_ed25519) never leaves your machine and must
stay chmod 600 — SSH will refuse to use a key that other users can
read. The public key (id_ed25519.pub) is what you hand out and append
to a server's ~/.ssh/authorized_keys.
This same key pair is what you'll register with GitHub for Git access, and the same authentication model (a keypair a service trusts) reappears as AWS access keys in Week 8 and Kubernetes service account tokens in Week 11 — the underlying idea doesn't change even as the tool does.
5. Hands-on Exercise
Write a system health-check script
Combine this week's filesystem, process and Bash skills into one small but genuinely useful tool.
Requirements:
- Set up WSL2 (Windows) or confirm your Linux/macOS terminal, then install
git,curlandjqwith your package manager. - Generate an SSH key pair with
ssh-keygen -t ed25519and confirm the private key ischmod 600. - Write
healthcheck.shwithset -euo pipefailthat reports: disk usage percentage on/, the top 3 processes by memory usage (ps aux --sort=-%mem | head -4), and the number of files in/var/log. - Make the script accept an optional disk-usage threshold as its first argument (default
80), andexit 1with a clear message if usage is at or above it. - Make it executable with
chmod +x healthcheck.shand run it as./healthcheck.sh 90.
Reuse the disk-usage line from the check-disk.sh example above rather than reinventing it — real ops scripts are built by composing small, previously-proven pieces, not by writing everything from scratch each time.
6. Knowledge Check
Four quick questions. Expand each to check your answer.
Q1
What does chmod 750 deploy.sh actually set?
What does chmod 750 deploy.sh actually set?
Owner permissions to 7 (read+write+execute, 4+2+1), group permissions to 5 (read+execute, 4+1), and permissions for everyone else to 0 (none). Each digit is an independent sum of read(4)/write(2)/execute(1) for one of the three audiences: owner, group, others.
Q2
Why does set -euo pipefail matter at the top of a Bash script?
Why does set -euo pipefail matter at the top of a Bash script?
-e stops execution the moment any command exits with a failure, instead of silently continuing; -u turns a reference to an unset variable into an error rather than an empty string; and pipefail makes a pipeline like cmd1 | cmd2 fail if either command fails, not just the last one. Without these, scripts can silently limp forward after a real failure and cause damage several lines later.
Q3
Why does SSH refuse to use a private key that isn't chmod 600?
Why does SSH refuse to use a private key that isn't chmod 600?
A private key proves your identity to every server that trusts its matching public key. If group or other users on the machine could read it (permissions looser than owner-only read/write), anyone with local access could impersonate you on any server you can reach — so SSH enforces owner-only access as a safety check rather than trusting you to remember it.
Q4
Why quote a variable as "$file" instead of writing $file in a script?
Why quote a variable as "$file" instead of writing $file in a script?
Unquoted, Bash performs word-splitting on the variable's value — a filename containing a space (like "march report.log") becomes two separate arguments instead of one, which silently breaks commands like cp or a for loop. Quoting preserves the value as a single argument regardless of spaces or other special characters inside it.