logo
NotesNotesResumeResume
© 2026 Kiet Nguyen
← All notes
Maximalist Y2K chrome portal pouring a rainbow byte stream — everything is a file

Breakdown·January 23, 2026·8 min read

Decoding “Everything is a file”

Linux · Unix · Systems

Unix’s most quoted slogan is a design contract, not poetry: many resources share open, read, write, and close. What “file” means, where the metaphor is honest, and where it bends.

“Everything is a file” shows up on stickers and one-line answers that end the conversation without explaining anything. This note is a breakdown of the slogan: what the contract actually is, what “file” means, the everyday surfaces it shows up on, and where the metaphor bends.

One-sentence crystal

Everything is a file means many kernel-managed resources share a uniform path + file-descriptor interface (open, read, write, close, and kin)—not that every object is a disk blob or that cat is always the right tool.


The slogan is a uniform interface

Taken literally, the phrase is false: a serial port is not a PDF. Taken as system design, it is sharp:

Many different kernel-managed resources are exposed through the same family of operations—open (or openat), read, write, close, and often ioctl / mmap / poll—so programs and shell tools do not need a new API for every kind of object.

Casual readingUseful reading
“Disk bytes and devices are the same thing”“I can name many resources with paths and talk to them with a small set of syscalls”
“cat works on everything forever”“cat works on anything that behaves like a byte stream under the VFS”
“No special cases”“Special cases still exist; the file model is the default door”

A more accurate form of the phrase is sometimes “everything is a file descriptor” or “everything is a stream of bytes”: the resource need not have a filename or live on a physical disk—it only needs to behave like a stream you can read from or write to.

So “everything is a file” really means: everything that can usefully wear a file descriptor often does.


What “file” means here

In this context, a file is not “something in a folder on disk.” It is closer to:

  1. An object the kernel tracks (identity + operations).
  2. Often a path in a hierarchical namespace (/, mount points).
  3. After open, a file descriptor (a small integer in your process) that stands for “this open instance with these flags and this offset/mode.”
path  ──open()──►  file descriptor (fd)
                      │
                      ├── read / write / lseek
                      ├── ioctl / mmap / fcntl
                      └── close

Paths are for finding. FDs are for using.

LayerExampleWhat you hold
Path name/etc/hosts, /dev/ttyUSB0, /proc/self/statusString the VFS resolves
Open fileResult of open(...)FD 3, 4, … in this process
Underlying objectRegular file, socket, pipe, device, pseudo-fileKernel object with ops

Two processes can open the “same” path and get different FDs with different offsets and flags.


Four places the idea shows up every day

1. Regular files and directories

Disk-backed bytes and directory entries—what non-Unix people usually mean by “file.” Unix adds:

  • Everything is bytes at the read/write level.
  • Metadata (mode, owner, timestamps, size) lives beside content.
  • Directories are special: list, link, unlink—not free-form byte stores you should rewrite with echo.

2. Devices under /dev

Character and block devices are nodes that look like files:

ls -l /dev/null /dev/zero /dev/urandom /dev/tty 2>/dev/null
Node (typical)“File” behaviorReality
/dev/nullWrite discards; read returns EOFKernel black hole
/dev/zeroRead returns zerosInfinite zero source
/dev/urandomRead returns entropy bytesRandomness as a stream
/dev/ttyUSB0read/write serial trafficHardware as a stream
Block deviceOften raw sector I/ODisk/partition—dangerous if misused
# Same tools; different objects
echo hello > /tmp/note.txt
echo hello > /dev/null          # disappears on purpose
head -c 16 /dev/urandom | xxd   # binary “file” that is not on disk

3. Process and kernel state under /proc and /sys

Pseudo-filesystems: no real disk file behind most paths. Read to observe; sometimes write to configure.

cat /proc/self/status | head
cat /proc/meminfo | head
ls /sys/class/net
cat /sys/class/net/lo/operstate
TreeMental model
/procProcess table + some system snapshots as files
/sysDevices, drivers, and attributes as a navigable tree
/proc/sysTunables as files

The namespace is the API surface for a large class of operations: shell tools work without a separate “system API client” for every knob.

4. Pipes, sockets, and stdio

Pipes and many sockets are also FD-backed. The shell’s | is the slogan’s social form:

dmesg | grep -i error | tail -n 20

Each stage reads a stream and writes a stream. Filters compose because the interface is the same shape.

Standard streams are FDs by convention:

FDNameUsual meaning
0stdinInput stream
1stdoutNormal output
2stderrDiagnostics

Redirection (>, 2>, 2>&1) rearranges which objects those FDs point at—a file, /dev/null, or a pipe.


Decoding table: what you can do

You see…Treat it as…Typical opsTrap
Path under home or /etcPersistent bytes + metadatacat, editors, statPermissions, atomic replace
/dev/tty* and friendsByte stream to hardwareserial tools, open in a programBaud, exclusive open, access rights
/proc/<pid>/…Live process snapshotcat, lsValues change under you
/sys/...Driver/hardware attributecat / careful writeWrong write can break devices
Pipe / FIFOStream between processesshell pipe, mkfifoBuffering, SIGPIPE
SocketConnection endpointnetwork tools, app protocolsNot always a path you can ls
DirectoryNamespace nodels, find, mkdirNot a flat byte file

Many resources share path + file-descriptor I/O so the same tools and syscalls apply; that does not mean every object is a disk blob or that cat is always the right tool.


What the slogan depends on

Virtual File System (VFS). Different backends (disk filesystems, tmpfs, procfs, sysfs, device nodes) plug into one layer so open/read look similar upstairs. Uniformity is an abstraction.

Permissions. A path that looks like a file still has mode bits, ownership, and sometimes stricter policy. “I can see the path” ≠ “I may open it.”

Text when it is text. Many /proc and /sys attributes are human-readable on purpose.


Where the slogan bends

PressureWhat happens
Sockets and some IPCOften FDs, but not always a comfortable path name; protocols live above raw bytes
ioctl and private APIsDevice-specific commands that are not portable read/write semantics
Complex devicesMay expose a node yet need specialized APIs beyond a byte stream
Non-seekable “files”Pipes and many devices: no meaningful lseek; size may be zero or meaningless
Containers / namespacesThe same path string can mean different objects in different views

Mature form of the slogan:

Prefer a file-like interface when it reduces special cases—without pretending special cases vanished.


A five-minute drill

On any Linux box you are allowed to use:

# 1) Same command family, three object kinds
wc -c /etc/hosts
wc -c /proc/version
# wc -c /dev/zero   # infinite “file” — Ctrl-C when you have the idea

# 2) FDs for this shell
ls -l /proc/self/fd

# 3) Where does this path really live?
readlink -f /etc/hosts
findmnt -T /etc

If those steps feel obvious, you already use the slogan.


Prefer precise language

Avoid sayingPrefer saying
“Everything is a file, so Linux is simple”“Linux exposes many resources through a uniform file/FD interface”
“Just cat the device”“If it is a byte stream device node, stream tools may work; check mode and docs”
“/proc is the filesystem”“/proc is a pseudo-filesystem projecting kernel state as files”
“Namespaces break the model”“Namespaces rebind the view; the model still holds inside that view”

Guess what?

The commands you type every day are files too, not a separate magic class of object.

When you run ls, grep, or a helper script, the shell resolves a path (via PATH), opens that object, and executes it. Same namespace; same “look it up, then use it” story.

type ls
# often: ls is /bin/ls   (or hashed, or a shell builtin—type will say)

command -v grep
which python3   # if which is installed

If the resolved path is a script (starts with #!), you can often just read it:

# Example shape—paths differ by distro
file "$(command -v update-alternatives)"   # may say "shell script"
# cat "$(command -v some-helper-script)"  # open the text; edit with care

If it is a compiled binary, cat will dump noise (or mess your terminal). Prefer:

file "$(command -v ls)"     # ELF executable, …
less "$(command -v ls)"     # optional; binary, not a novel

Builtins (cd, type itself in bash) are the honest exception: they live inside the shell, so there is no separate path to cat. Everything else you “just run” is still, under the slogan, a named object in the filesystem—or a stream once it is open.

The surprise is not that programs are special. The surprise is that they never left the model: find the path, treat it as a file, and only then worry about “is this text I can read, or a binary I should not.”


Closing

Decode the phrase as interface uniformity + hierarchical naming + file descriptors, not as ontology. Use it to navigate regular files, /dev, /proc, /sys, pipes, and stdio without fear. Drop it when the problem needs a real protocol, a real ioctl, or a specialized API.

If you can open the right path, read the right stream, and know whether you are holding a disk object, a device stream, or a synthetic control surface, you are practicing what the slogan was for.

Back to notes

Was this page helpful?