1.3. The Filesystem Hierarchy and Linux Abstractions
💡 First Principle: The Linux Filesystem Hierarchy Standard (FHS) exists to make Linux predictable across all distributions — any trained administrator should be able to find configuration files, logs, and binaries in the same places regardless of whether they're on Ubuntu, RHEL, or openSUSE. The hierarchy also encodes purpose: where something lives tells you what it is.
Without the FHS, every distribution would organize files differently, making cross-distribution knowledge worthless. The FHS is an agreement — not enforced by the kernel, but followed by distributions so that tools, documentation, and administrators can work reliably across the ecosystem.
⚠️ Common Misconception: /bin and /usr/bin contain different kinds of binaries. On modern systems they are typically the same directory via symlink — /bin → /usr/bin. The historical separation (essential vs non-essential binaries) is a legacy concept that no longer reflects reality on most distributions.
The FHS Directory Structure
/ ← Root of the entire filesystem
├── /bin ← Essential binaries (ls, cp, cat). Historically kept separate so it worked
│ even if /usr was unmounted; on UsrMerge systems it is now → /usr/bin
├── /boot ← Kernel, initramfs, and GRUB config
├── /dev ← Device files (disks, terminals, null, random)
├── /etc ← System-wide configuration files (text format)
├── /home ← User home directories (/home/alice, /home/bob)
├── /lib ← Shared libraries for /bin and /sbin binaries
├── /proc ← Virtual filesystem: kernel runtime information (not on disk)
├── /sbin ← System binaries (root-only administrative tools)
├── /tmp ← Temporary files (cleared on reboot; world-writable)
├── /usr ← User programs, libraries, documentation
│ ├── /usr/bin ← Most user commands (python3, git, vim)
│ ├── /usr/lib ← Libraries for /usr/bin programs
│ └── /usr/local ← Locally compiled/installed software (overrides /usr)
└── /var ← Variable data: logs, databases, mail spools
├── /var/log ← System and application logs
└── /var/lib ← Persistent application data (databases, package state)
The /proc Virtual Filesystem
/proc is one of Linux's most powerful abstractions — it's a filesystem that doesn't exist on disk at all. The kernel generates its contents dynamically at read time. Reading /proc/cpuinfo triggers kernel code that formats CPU information as text. Writing to /proc/sys/net/ipv4/ip_forward changes a live kernel parameter without requiring a reboot.
cat /proc/cpuinfo # CPU architecture, cores, speeds
cat /proc/meminfo # Memory usage breakdown
cat /proc/1/cmdline # Command line that started PID 1 (systemd)
cat /proc/mounts # Currently mounted filesystems
echo 1 > /proc/sys/net/ipv4/ip_forward # Enable IP forwarding (non-persistent)
This is why /proc/<PID>/ directories appear and disappear as processes start and stop — the directory is the process, from the kernel's perspective.
The /dev Virtual Filesystem
/dev contains device files — the concrete implementation of "everything is a file." Two types matter most for the exam:
| Device Type | Description | Examples |
|---|---|---|
| Block devices | Transfer data in fixed-size blocks; buffered | /dev/sda (disk), /dev/nvme0n1, /dev/sdb1 (partition) |
| Character devices | Transfer data one character at a time; unbuffered | /dev/tty (terminal), /dev/null, /dev/random, /dev/urandom |
| Special character | Kernel-provided pseudo-devices | /dev/null (discard), /dev/zero (zero stream), /dev/urandom (random bytes) |
ls -la /dev/sda # brw-rw---- — 'b' = block device
ls -la /dev/tty # crw-rw-rw- — 'c' = character device
udev (part of systemd) dynamically manages /dev — when you plug in a USB drive, udev detects the kernel event, applies matching rules, and creates the appropriate /dev/sdX entry with the right permissions.
Understanding Path Types
Linux uses two path styles, and confusing them causes real problems:
# Absolute paths — start from root, unambiguous regardless of where you are
/etc/nginx/nginx.conf
/home/alice/.ssh/authorized_keys
~ # Shorthand for your home directory (/home/alice)
# Relative paths — start from current directory (pwd)
./script.sh # Script in current directory
../config # Go up one level, then into config
- # Previous directory (cd -)
The PATH environment variable is a colon-separated list of directories the shell searches when you type a command name without a path. When you type ls, the shell finds /usr/bin/ls by searching through PATH. If you create a script named ls in your home directory, it won't run unless ~/bin is in PATH or you invoke it as ./ls.
Configuration Lives in /etc
Every service on Linux reads its configuration from text files in /etc. This is by design: text files are version-controllable, diffable, and human-readable. The sysctl command reads from /etc/sysctl.conf and /etc/sysctl.d/ to set persistent kernel parameters. The SSH daemon reads /etc/ssh/sshd_config. The package manager reads repository definitions from /etc/apt/sources.list.d/ or /etc/yum.repos.d/.
Understanding that configuration is in /etc in text files means you can audit, backup, and reproduce any system configuration using standard text tools.
⚠️ Exam Trap: /tmp is world-writable but its contents are cleared on reboot. /var/tmp is also world-writable but persists across reboots. Applications that need temporary files that survive a reboot should use /var/tmp, not /tmp. Getting this wrong in a scenario question about application data loss after a reboot is a common trap.
Reflection Question: A junior admin tells you she "can't find the log files for nginx" because /var/log/nginx/ doesn't exist. Before suggesting anything, what two questions would help you diagnose the most likely causes?