Everything Is a File: Devices, /proc & File Descriptors
- Explain the Unix 'everything is a file' model: hardware, kernel state, and pipes all present the same read/write interface
- Read the first character of ls -l to name a file's type (- d l c b p s)
- Recognize device files in /dev (/dev/null, /dev/zero, /dev/random) and what reading or writing them does
- Read live kernel state from /proc and /sys as if it were files, and name the three standard file descriptors (0/1/2)
The big idea: one interface for everything
See why Unix models hardware, kernel state, and channels all as files — so one small toolset works on all of them.
There's a phrase you'll hear constantly in the Unix world: "everything is a file." It's the single idea that ties the whole system together, and once it clicks, a lot of Linux stops feeling like a pile of special cases.
Here's what it means. A regular file is an object you can open, read bytes from, write bytes to, and close. Unix takes that same simple interface and uses it for almost everything else too:
- Your disk, your terminal,
/dev/null— hardware and devices appear as files. - Kernel state — how much memory is free, what your CPU is — appears as files under
/procand/sys. - Pipes and network sockets — the channels data flows through — are file-like too.
Why do this? Because it means one small set of tools works on all of them.
cat,>,<, and the read/write system calls don't care whether they're touching a text file, a disk, or the kernel's memory stats — it's all "open it, read/write bytes, close it." You already know how to read a file withcat; that same knowledge lets you read your CPU info or send data to the void. Instead of a hundred special commands, you learn the file interface once and apply it everywhere.Check yourself
In the 'everything is a file' model, what single interface do regular files, devices, and kernel state all share?
- Your disk, your terminal,
The file-type zoo: read the first character of ls -l
Name a file's type from the first character ls -l prints.
If everything is a file, then files come in kinds — and Unix tells you which kind right up front. The very first character of each
ls -lline is the file type:- `-` a regular file (text, a program, an image — ordinary data)
- `d` a directory (itself just a file that lists other files)
- `l` a symbolic link (a pointer to another path)
- `c` a character device (a device you read/write a stream of bytes from, like a terminal)
- `b` a block device (a device addressed in blocks, like a disk)
- `p` a named pipe (a FIFO — a file-like channel between programs)
- `s` a socket (a channel, often for network or local communication)
So when you run
ls -land a line starts withd, it's a directory;lis a link;corbis a device. That one character is the answer to "what kind of file is this?" — and it's why a directory can be listed like a file: to Unix, it is one, just a special kind whose contents are a list of names.ls -l /dev/null /etc/hostname /etccrw-rw-rw- 1 root root 1, 3 /dev/null -rw-r--r-- 1 root root 8 /etc/hostname drwxr-xr-x 1 root root 4096 /etc
Three different types, told by the first character. /dev/null starts with 'c' — a character device. /etc/hostname starts with '-' — a regular file. /etc starts with 'd' — a directory. Same ls, same output shape; the leading letter is what kind of file each one is. Check yourself
An ls -l line begins with the character 'l'. What kind of file is it?
Device files: hardware as files in /dev
Meet the device files in /dev and what reading or writing them does.
The directory `/dev` is where the "everything is a file" idea gets vivid: it's full of device files that stand in for real (and virtual) hardware. Reading or writing them talks to the device or the kernel. The famous ones:
- `/dev/null` — the void. Anything you write to it is discarded; reading it gives nothing (instant end-of-file). This is why
command > /dev/nullmeans "throw the output away." - `/dev/zero` — an endless stream of zero bytes, used to fill or blank things.
- `/dev/random` / `/dev/urandom` — a stream of random bytes from the kernel, used to generate keys and passwords.
- `/dev/sda`, `/dev/nvme0n1` — your actual disks (block devices).
- `/dev/tty` — your terminal itself.
The point: you interact with all of these using the same file operations. Writing to
/dev/nulluses the same redirection you'd use to write a text file — the destination just happens to be "nowhere." This uniformity is the payoff of the model:> /dev/nullisn't a special "discard" command, it's ordinary redirection aimed at a device file that eats its input.echo 'this disappears' > /dev/null; echo "exit status: $?"exit status: 0
We redirect echo's output to /dev/null — the void — so the text is silently discarded (nothing prints). The command still succeeds (exit status 0). This is the everyday way to run something and throw away its output: ordinary redirection, aimed at a device file. head -c 8 /dev/zero | wc -c8
Read 8 bytes from /dev/zero (an endless stream of zero bytes) and count them with wc -c. /dev/zero behaves exactly like a file you can read from — it just never runs out. Same read interface, virtual source. - `/dev/null` — the void. Anything you write to it is discarded; reading it gives nothing (instant end-of-file). This is why
/proc, /sys and file descriptors: the kernel as files
Read live kernel state from /proc and /sys, and name the standard file descriptors.
Two special directories expose the kernel itself as files:
- `/proc` — live information about the system and every running process.
/proc/cpuinfodescribes your CPU,/proc/meminfoyour memory, and/proc/<pid>/a directory per running process. These aren't real files on disk — the kernel generates them the moment you read them, so they're always current. Youcatthem like any file. - `/sys` — a similar view of devices and kernel settings, often writable: echoing a value into the right
/sysfile changes a hardware or kernel setting.
This is "everything is a file" at its most powerful: to ask the kernel how much memory is free, you don't call a special API — you read a file.
The same idea reaches inside your own programs as file descriptors. When a program opens a file, the kernel hands it a small number — a file descriptor (fd) — to refer to that open file. Three are always set up for you:
- `0` — stdin (standard input)
- `1` — stdout (standard output)
- `2` — stderr (standard error)
That's what the numbers in redirection are:
2>means "redirect file descriptor 2 (stderr)." You can even see a process's open files as a directory:/proc/self/fd/lists the file descriptors of the current process — files, all the way down.grep -m1 MemTotal /proc/meminfoMemTotal: 16305936 kB
Read the kernel's live memory info straight out of /proc/meminfo with grep — no special 'memory' command needed, just reading a file. The kernel produced this line the instant grep opened the file, so it's always up to date. Your value will differ. ls -l /proc/self/fd/lrwx------ 1 user user 64 0 -> /dev/pts/0 lrwx------ 1 user user 64 1 -> /dev/pts/0 lrwx------ 1 user user 64 2 -> /dev/pts/0
The open file descriptors of the current process, shown as links. 0, 1, and 2 are stdin, stdout, and stderr — here all pointing at the terminal (/dev/pts/0). This is the file model turned inward: your program's open files are themselves listed as files. Check yourself
Which file descriptor number does the redirection '2>' operate on, and what stream is it?
- `/proc` — live information about the system and every running process.
Now do it — prove everything is a file
Read a device, read kernel state, and watch redirection target a device file.
One continuous experiment that makes the model concrete: identify file types, read from a virtual device, pull live kernel state, and send output into the void — all with the same handful of file tools.
for f in /etc/hostname /etc /dev/null /dev/sda; do printf '%s ' "$f"; ls -ld "$f" 2>/dev/null | cut -c1; done/etc/hostname - /etc d /dev/null c /dev/sda b
Loop over four paths and print just the first ls -l character of each: a regular file (-), a directory (d), a character device (c), and a block device (b). Four different kinds of thing, one uniform way to ask 'what type are you?' cat /proc/loadavg; echo '--- uptime the file way ---'; cut -d' ' -f1 /proc/uptime0.12 0.08 0.05 1/234 5678 --- uptime the file way --- 1394.52
cat the kernel's live load average from /proc/loadavg, then read the first field of /proc/uptime (seconds since boot). Both are kernel state served as files — you 'read the system' by reading files. Your numbers will differ. yes | head -3 | tee /dev/null; echo '--- and discard entirely ---'; yes | head -3 > /dev/null && echo 'output went to the void'y y y --- and discard entirely --- output went to the void
First tee copies the stream to /dev/null AND to the screen (so you see the y's). Then the same stream is redirected wholly to /dev/null — nothing prints, but the command still succeeds. Writing to a device file is just writing to a file whose destination happens to be 'nowhere'.
- 'Everything is a file' means hardware, kernel state, pipes and sockets all present the same open/read/write/close interface — so cat, redirection, and the read/write calls work on all of them, and you learn one interface instead of a hundred commands.
- The first character of an ls -l line names the file type: - regular, d directory, l symlink, c character device, b block device, p named pipe (FIFO), s socket.
- /dev holds device files: /dev/null discards what you write (that's what > /dev/null does), /dev/zero and /dev/random are endless streams, /dev/sda is a disk. Reading/writing them uses ordinary file operations.
- /proc and /sys expose live kernel state as files you cat (e.g. /proc/meminfo) — generated on read, always current. File descriptors 0/1/2 are stdin/stdout/stderr, which is what redirections like 2> operate on.
| File / type | What it is |
|---|---|
| ls -l first char -/d/l | regular file / directory / symlink |
| ls -l first char c/b | character device / block device |
| ls -l first char p/s | named pipe (FIFO) / socket |
| /dev/null | the void — writes discarded, reads give EOF |
| /dev/zero, /dev/random | endless streams of zeros / random bytes |
| /proc/meminfo, /proc/<pid> | live kernel & process state, served as files |
| fd 0 / 1 / 2 | stdin / stdout / stderr (what 2> redirects) |
