open atlas
↑ Back to track
Command line CLI · 03 · 01

stdin, stdout, and stderr

Every process starts with three open file descriptors: stdin (fd 0) reads input, stdout (fd 1) writes normal output, stderr (fd 2) writes errors. Understanding these three streams is the foundation of shell pipelines.

CLI Foundations ◷ 18 min
Level
FoundationsJuniorMiddleSenior

Every command you run — ls, cat, grep — reads from somewhere and writes to somewhere. You’ve seen text appear in your terminal when you run commands, but you probably haven’t thought about where that text goes or how errors end up mixed in with normal output. The shell gives every process three open channels from the moment it starts. Understanding these three channels is what makes pipelines and redirection make sense.

By the end of this lesson you will know what stdin, stdout, and stderr are, which file descriptor number each one carries, and why keeping errors on a separate stream matters.

Goal

After this lesson you can name the three standard streams, state their file descriptor numbers (0, 1, 2), explain what each one is used for, and describe why stderr is kept separate from stdout.

1

Every process inherits three open file descriptors. When the kernel starts any process, it hands it three already-open file descriptors — numeric handles that refer to open files or devices. The kernel assigns small integers:

  • fd 0 — standard input (stdin)
  • fd 1 — standard output (stdout)
  • fd 2 — standard error (stderr)

A file descriptor is just a number the process uses to read from or write to something. The kernel keeps a table mapping each number to the actual resource (a terminal device, a file, a pipe). The three standard descriptors are conventions that every Unix program relies on.

2

stdin (fd 0) is where a process reads its input. By default, stdin is connected to the keyboard — the terminal device. When you run a command that reads input (cat with no arguments, read, grep without a filename), it blocks waiting for you to type. Whatever you type goes into fd 0.

cat
hello world
hello world
^D

cat with no filename reads from stdin until it sees end-of-file (sent by pressing Ctrl+D). It echoes each line back to stdout as it reads it.

3

stdout (fd 1) is where a process writes normal output. By default, stdout is connected to the terminal screen. When ls lists files, or echo prints a string, those bytes go to fd 1. Because both stdout and stderr default to the same terminal screen, you normally can’t tell them apart visually — they both appear as text in your terminal.

echo "Hello from stdout"

Output:

Hello from stdout

That line went to fd 1 → terminal screen.

4

stderr (fd 2) is where a process writes error and diagnostic messages. It is also connected to the terminal screen by default, but it is a separate channel from stdout. Programs write errors, warnings, and progress messages to fd 2 so they don’t contaminate the normal data stream on fd 1.

ls /nonexistent

Output:

ls: cannot access '/nonexistent': No such file or directory

That error message went to fd 2, not fd 1. When both streams flow to the same terminal you see them interleaved, but they are physically separate file descriptors — which means you can redirect them independently.

Why does this separation matter? If a script produces 10 000 lines of output that another tool will process, any error messages mixed into fd 1 would corrupt the data. Keeping errors on fd 2 means the consumer of fd 1 always sees clean output.

5

The shell connects these streams to the terminal by default, but you can rewire them. The terminal is just the default target. The shell can point fd 0 at a file (so a program reads from a file instead of the keyboard), point fd 1 at a file (so output is saved instead of printed), or connect fd 1 of one process to fd 0 of another (a pipe). All of that machinery — redirection and pipes — is built on top of these three file descriptors. You’ll learn the syntax in the next lessons; for now, know that fd 0, 1, and 2 are the plumbing that makes it possible.

Worked example

Seeing stdout and stderr separately.

Run a command that produces both normal output and an error in one invocation:

ls /etc/hosts /nonexistent

Output (interleaved on the terminal):

ls: cannot access '/nonexistent': No such file or directory
/etc/hosts

The error line came from fd 2 and the file listing from fd 1. They appear together because both streams default to the terminal. Now redirect stdout to a file to see them separated:

ls /etc/hosts /nonexistent > /tmp/out.txt

Terminal shows (only stderr, because stdout went to the file):

ls: cannot access '/nonexistent': No such file or directory
cat /tmp/out.txt
/etc/hosts

The two streams were always separate — the terminal just happened to display both in the same window.

Why this works

On macOS, the same three standard streams exist with the same file descriptor numbers. The kernel and C library are different, but the POSIX convention (fd 0/1/2 = stdin/stdout/stderr) is identical. Every Unix-derived system follows it.

Common mistake

A common confusion: stderr is not “less important” — it is just separate. Many programs write progress bars, debug info, and verbose logs to stderr so they don’t pollute stdout. When you redirect stdout to a file, all those messages still appear in the terminal because they go to stderr. This is intentional design, not a bug.

Check yourself
Quiz

A program writes an error message. Which file descriptor does it use by convention?

Recap

Every process starts with three standard file descriptors: fd 0 (stdin) for reading input, fd 1 (stdout) for writing normal output, and fd 2 (stderr) for writing error and diagnostic messages. By default all three are connected to the terminal, so both output streams appear on screen. Keeping errors on a separate stream (fd 2) means the consumer of fd 1 always gets clean data — and the shell can independently redirect or pipe each stream. This three-descriptor model is the foundation that makes all shell redirection and pipelines work.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 5 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.