Signal9Signal9 — home
online
all lessons

Everything Is a File: Devices, /proc & File Descriptors

Beginner25 min5 steps
What you'll learn
  • 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)
  1. 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 /proc and /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 with cat; 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?

  2. 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 -l line 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 -l and a line starts with d, it's a directory; l is a link; c or b is 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 /etc
    crw-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?

  3. 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/null means "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/null uses 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/null isn'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 -c
    8
    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.
  4. /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/cpuinfo describes your CPU, /proc/meminfo your 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. You cat them like any file.
    • `/sys` — a similar view of devices and kernel settings, often writable: echoing a value into the right /sys file 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/meminfo
    MemTotal:       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?

  5. 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/uptime
    0.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'.
Recap
  • '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.
Everything is a file — at a glance
File / typeWhat it is
ls -l first char -/d/lregular file / directory / symlink
ls -l first char c/bcharacter device / block device
ls -l first char p/snamed pipe (FIFO) / socket
/dev/nullthe void — writes discarded, reads give EOF
/dev/zero, /dev/randomendless streams of zeros / random bytes
/proc/meminfo, /proc/<pid>live kernel & process state, served as files
fd 0 / 1 / 2stdin / stdout / stderr (what 2> redirects)