Why Linux Uses 0, 1, 2 for Standard Input, Output, and Error – A Deep Dive
This article explains the origins and purpose of Linux's standard input (0), standard output (1), and standard error (2) file descriptors, shows how they are defined in Rust and Go, and illustrates their behavior in terminal emulators and SSH sessions with detailed diagrams.
0x01 What Are Standard Input, Output, and Error?
In Linux these three streams are simply file descriptors: standard input is 0, standard output is 1, and standard error is 2. The same numbers appear in many programming languages.
For example, Rust defines them as:
where libc::STDIN_FILENO, libc::STDOUT_FILENO, and libc::STDERR_FILENO have the values 0, 1, and 2 respectively:
Go uses analogous constants:
where syscall.Stdin, syscall.Stdout, and syscall.Stderr map to 0, 1, and 2.
0x02 Why 0/1/2?
The numbers are merely a convention; the Linux kernel treats them like any other file descriptor. They were chosen because file descriptors are allocated sequentially starting at 0, so the first three naturally became the standard streams.
0x03 Why Keep This Convention?
The convention lets different components of the Linux ecosystem cooperate. For instance, a terminal emulator knows that a newly spawned bash process will have its stdin, stdout, and stderr on descriptors 0, 1, and 2, so it can attach those descriptors to the terminal’s pseudo‑terminal (pty) device.
Similarly, when bash runs another program, it can simply redirect the child’s descriptor 1 or 2 to a file without needing to know any special identifiers.
0x04 Why Three Descriptors Instead of One?
Although the three descriptors often point to the same underlying file (the terminal’s pty slave), having separate descriptors provides flexibility. It allows a process to redirect its output or error streams independently, e.g., ./hello > a.log redirects only stdout while stdin and stderr remain attached to the terminal.
0x05 What Is a File Descriptor?
In the Unix philosophy, “everything is a file.” When a process opens a socket, creates an epoll instance, or opens a regular file, the kernel represents the underlying object with a struct file and stores a pointer to it in the process’s file descriptor table. The index in that table is the file descriptor (fd).
System calls return an fd to user space; subsequent calls pass that fd back to the kernel so it can locate the correct struct file and perform the requested operation.
0x06 Where Do 0/1/2 Point?
The actual target of a process’s standard streams depends on the execution environment and any redirections performed. The following examples illustrate typical scenarios.
0x07 Running hello in a Terminal Emulator
The user types ./hello in the terminal. The command travels through the kernel’s pty channel to bash’s stdin (fd 0). Bash forks a child process to run hello. The child writes “hello” to stdout (fd 1) and “world” to stderr (fd 2). Both streams travel back through the pty master to the terminal emulator, which displays the output. In this case, the child’s 0/1/2 all refer to the pty slave end.
0x08 Running hello via SSH
The user logs into a remote host with ssh and runs ./hello. The command travels from the local terminal’s pty to the local ssh process’s stdin, then is written to a TCP socket. The remote sshd reads the command from its socket, writes it to its own pty master, and the remote bash receives it on stdin. The remote hello writes to its stdout/stderr, which travel back through the remote pty, are read by sshd, sent over the socket, and finally displayed on the local terminal emulator. Throughout, each hello process’s descriptors point to the slave side of the remote pty.
0x09 Running hello via SSH with Output Redirection
This scenario is identical to the previous one except that the remote hello process’s stdout (fd 1) is redirected to a file a.log. The redirection is performed by the shell before hello starts, so the data no longer travels back to the terminal emulator.
These examples demonstrate how the simple 0/1/2 convention enables flexible I/O handling across local and remote environments.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
