PHASE 2 — Linux fundamentals
You now know what the OS is doing underneath. This phase is fluency: the commands and mental models you'll use every single day, hands-on, until they stop feeling like memorisation.
Part 7 — The filesystem hierarchy and navigation
Parts 1–6 covered the OS's internals; this part and the next few turn practical. It starts with Linux's own organizing idea — that (almost) everything is a file — and the directory hierarchy that idea produces: the map you need before the command-heavy parts that follow make any sense.
Chapter 23 — Everything is a file (almost)
In one sentence
Unix's defining design choice is that files, directories, devices, pipes, and even kernel information are all accessed through the SAME simple interface — open, read, write, close — which is exactly why Linux's command-line tools compose so well together.
Why this matters
Once you internalise this, half of Linux stops looking like a pile of unrelated commands and starts looking like one consistent idea, applied everywhere.
How it actually works
A FILE DESCRIPTOR (Chapter 2 introduced this) is just a small integer
a process uses to refer to something it has open. Every process gets
three, by convention, at startup:
0 stdin (standard input)
1 stdout (standard output)
2 stderr (standard error)
But a file descriptor can point at FAR more than a regular file:
a directory, a device (`/dev/sda`, your disk), a pipe (Chapter 19), a
network socket, or a purely VIRTUAL file the kernel generates on the
fly.
THE VIRTUAL FILESYSTEMS ARE THE CLEAREST DEMONSTRATION of this
philosophy taken all the way:
/proc a filesystem that doesn't correspond to anything on disk
AT ALL -- it's the kernel exposing its OWN internal state
(running processes, memory stats, CPU info) as if it were a
directory of files, generated live, on read.
/sys similar idea, focused on hardware/device and kernel
subsystem configuration.
/dev special files representing DEVICES -- `/dev/null` (discards
anything written to it, always returns end-of-file when
read), `/dev/random` (returns random bytes), `/dev/sda`
(your actual disk, as a stream of bytes).
THIS IS NOT JUST A CUTE ABSTRACTION -- it's WHY `ps`, `top`, and
`free` (Chapter 31) work at all: they don't use some special, secret
kernel API. They just READ FILES under /proc, the exact same `open`/
`read`/`close` syscalls (Chapter 2) your own program would use to
read a text file. You could write your own (much worse) version of
`ps` in a few lines of shell script, entirely from `/proc`.
Real-world example
The "everything is a file" philosophy didn't originate with Linux --
it traces back to Unix's earliest design (Ken Thompson and Dennis
Ritchie at Bell Labs, early 1970s) and was pushed even FURTHER by a
later Bell Labs research OS called Plan 9, whose designers extended
the idea to networking, graphics, and even PROCESS CONTROL, all
exposed as file operations. Linux's `/proc` filesystem (introduced in
the early 1990s) is a direct descendant of this same philosophy,
deliberately choosing to expose kernel internals as a browsable,
readable filesystem rather than inventing a separate, bespoke query
API. The practical payoff, today, is enormous and very real: any
tool that can read a file -- `cat`, `grep`, a shell script, a
monitoring agent, a config-management tool -- can ALSO inspect
process info, memory stats, or CPU details, with zero special
libraries, because it's just text files. Countless real monitoring
and diagnostic tools (from decades-old shell scripts to modern
observability agents) are built on nothing more exotic than reading
`/proc` on a schedule.
Try it yourself
# See your own process's file descriptors, live
ls -la /proc/self/fd/
# Watch `/dev/null` do exactly what it claims
echo "this vanishes" > /dev/null
cat /dev/null; echo "(nothing printed above -- always empty)"
# Read raw kernel information as plain text -- no special tool needed
cat /proc/cpuinfo | head -10
cat /proc/meminfo | head -5
cat /proc/version
# Write your OWN tiny "ps" using nothing but /proc and shell tools
for pid in /proc/[0-9]*; do
[ -r "$pid/comm" ] && echo "$(basename $pid): $(cat $pid/comm 2>/dev/null)"
done | head -10
Build it in Go
Everything ps and top display comes from files under /proc.
Chapter 79 builds a ps/top in Go from
/proc/<pid>/stat, status, and cmdline, including the parsing trap where a
process name contains spaces.
Common mistakes
- Thinking
/procfiles are "real" files on disk. They're generated live, on read, by the kernel — there's nothing to find if you look for them on the physical disk. - Assuming every kernel object behaves identically to a regular file.
Devices like
/dev/sdacan be read/written like a file, but writing the wrong bytes to the wrong offset can genuinely destroy data — this power comes with real risk. - Forgetting stdin/stdout/stderr ARE file descriptors 0/1/2. Redirection
syntax (
2>&1,>,<) is just telling the shell which file descriptor points where — not a separate, unrelated concept from everything else in this chapter.
Check yourself
- What does "everything is a file" actually mean, concretely?
- Name the three standard file descriptors every process starts with.
- Why can a tool like
psbe implemented entirely by reading files, with no special kernel API?
(Answers: Appendix E.)
Further reading
- Reference:
man 5 proc— the exhaustive list of what's exposed under/proc. - Book (free): OSTEP, "Files and Directories" chapter.
- History: search "Plan 9 everything is a file Bell Labs" for the research-OS lineage of this idea.