Beginner 4 min read Updated: Sep 11, 2026

Standard Streams (stdin, stdout, stderr), Pipes & Redirection Operators

Master POSIX standard I/O streams: File descriptors 0, 1, and 2, redirection operators (>, >>, 2>&1), pipelines (|), tee, and robust exit code handling in Bash.

The Unix philosophy is built around a core architectural tenet: "Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface."

At the foundation of this philosophy lies the concept of Standard I/O Streams. Understanding how the Linux kernel abstracts inputs and outputs through numeric file descriptors, and how the Bash shell redirects and chains these streams using operators and pipes, is essential for every systems administrator and automation engineer.

POSIX Standard File Descriptors: 0, 1, and 2

Whenever the Linux kernel launches a process, it automatically binds three fundamental I/O channels represented by numeric File Descriptors (FD):

File Descriptor Stream Name Default Source / Destination Functional Purpose
0 stdin (Standard Input) Keyboard / Terminal Feeds input data into the process for execution.
1 stdout (Standard Output) Display Terminal / Screen Transmits successful execution results and primary data stream.
2 stderr (Standard Error) Display Terminal / Screen Transmits error messages, diagnostics, and operational warnings.

Because both stdout and stderr render to the terminal screen simultaneously by default, users often fail to realize they are entirely separate streams. Separating them via shell redirection allows administrators to log errors independently from standard output.

Redirection Operators Deep Dive

The shell intercepts redirection operators before launching the command, modifying the process's file descriptor table:

Operator Description Practical Example Behavioral Effect
> Redirect stdout (overwrite) uname -r > kernel.txt Overwrites destination file with process stdout.
>> Redirect stdout (append) date >> uptime.log Appends process stdout to the end of the file.
2> Redirect stderr (overwrite) find / -name "*.conf" 2> errors.txt Captures permission denied errors into errors.txt while displaying clean output on screen.
2>> Redirect stderr (append) backup.sh 2>> backup_errors.log Appends error messages to an ongoing error log file.
< Redirect stdin from file mysql -u root db_prod < dump.sql Supplies the contents of a file as input to stdin.

Combining Streams: The 2>&1 Idiom

To capture both standard output and error diagnostics into a single unified log file, administrators use stream duplication:

# POSIX Standard Method: Redirect stdout to file, then duplicate stderr to stdout
command > output.log 2>&1

# Modern Bash Shortcut (equivalent behavior)
command &> output.log

Order of Operations Trap: The sequence of redirection matters! Executing command 2>&1 > output.log does not combine streams into the file. The shell evaluates left-to-right: it first redirects stderr to the current location of stdout (the terminal screen), and then redirects stdout to the file. As a result, errors still spill onto the terminal!

Discarding Unwanted Output: /dev/null

The special character device /dev/null (the Unix bit-bucket) discards all data written to it. To run a command silently in cron jobs or background scripts:

# Discard all output and all error messages completely
command > /dev/null 2>&1

Pipelines: Inter-Process Communication in Memory

The pipe operator (|) connects the stdout (FD 1) of the preceding process directly to the stdin (FD 0) of the succeeding process:

# Count how many users have /bin/bash as their default login shell
grep '/bin/bash' /etc/passwd | wc -l

# Identify the top 5 memory-consuming processes
ps aux --sort=-%mem | head -n 6

Pipes execute concurrently in separate subshells. Data flows through a kernel memory buffer without touching physical storage, making pipelines exceptionally fast and scalable.

Pipes Only Capture stdout: By default, the pipe operator (|) redirects only standard output (FD 1). Errors generated on stderr (FD 2) will still bypass the pipe and print directly to the terminal screen. In modern Bash, use |& to pipe both stdout and stderr together into the next command.

Splitting Streams with tee

When running long automation scripts, administrators often want to observe command progress live on screen while simultaneously logging output to disk. The tee utility acts as a T-junction splitter:

# Print output to terminal and simultaneously write to build.log
./build_kernel.sh | tee build.log

# Append to log file instead of overwriting (-a)
./deploy.sh | tee -a deployment.log

Pipeline Exit Codes & PIPESTATUS

In standard Bash execution, the return code ($?) of a pipeline reflects only the exit code of the final command in the chain:

# Even if 'cat' fails because file does not exist, 'grep' returns 1 (no match)
cat non_existent_file.txt | grep "test"
echo $?
# Output: 1 (grep's exit code, hiding cat's failure!)

In production enterprise scripts, use pipefail to ensure that failures anywhere in a pipeline trigger error handling:

# Enable pipefail: returns the exit code of the rightmost command that failed
set -o pipefail

# In Bash, inspect exit codes of every segment in the pipeline:
cat non_existent_file.txt | grep "test"
echo "${PIPESTATUS[@]}"
# Example Output: 1 1 (both commands failed)
Code copied to clipboard!