A Linux command can read from your keyboard, print useful data to the terminal, report an error somewhere else, or send its output directly into another command. Those connections are built from three standard streams.
Standard input, standard output, and standard error give command-line programs a shared way to receive data and report results. The shell can reconnect those streams to terminals, files, devices, or pipes without changing the program itself.
This lesson explains that model first, then uses safe commands to show redirection and pipelines in practice.
Linux programs normally begin with three standard streams: stdin for input, stdout for normal output, and stderr for diagnostics. They are represented by file descriptors 0, 1, and 2.
The shell uses operators such as <, >, >>, 2>, and | to reconnect those streams. A pipe sends one command’s standard output to the next command’s standard input.
- What stdin, stdout, and stderr represent.
- Why normal output and error output are separate streams.
- How overwrite, append, and input redirection differ.
- What a pipe connects—and what it does not connect.
- Why redirection order can change the result.
- How to test stream behavior safely in a temporary directory.
- 🧠 Start with Three Standard Streams
- stdin — 0
- stdout — 1
- stderr — 2
- Why stdout and stderr Are Separate
- Redirect Standard Output with > and >>
- Redirect Standard Input with <
- Redirect stderr with File Descriptor 2
- Why Redirection Order Matters
- 🔗 What a Pipe Actually Connects
- 🧪 Mini Lab: Follow Data Through the Streams
- 1. Create an isolated workspace
- 2. Redirect stdout into a file
- 3. Append one more line
- 4. Separate normal output from an error
- 5. Build a simple pipeline
- 6. Inspect and remove the temporary workspace
- ⚠️ Common Stream and Pipeline Mistakes
- Short Summary
🧠 Start with Three Standard Streams
When a process starts, it commonly receives three open file descriptors. A file descriptor is a small number a process uses to refer to an open input or output channel.
stdin — 0
Standard input supplies data to the program. In an interactive session, it is commonly connected to the terminal.
stdout — 1
Standard output carries the program’s ordinary result. It commonly appears in the terminal unless redirected.
stderr — 2
Standard error carries diagnostics and error messages independently from normal output.
The names describe roles, not permanent destinations. Standard output does not inherently mean “the screen,” and standard input does not inherently mean “the keyboard.” Those are common defaults for an interactive command, but the shell can replace them.
This is possible because many Unix-style programs are designed to read a stream and write streams rather than controlling a particular terminal window themselves.
Why stdout and stderr Are Separate
A command may produce useful data and a diagnostic message during the same run. Keeping those outputs separate lets you save or pipe the useful result while still displaying an error.
Imagine a command that examines several paths. Information about readable paths can go to stdout, while messages about inaccessible or missing paths can go to stderr. A script can process the first stream without accidentally treating an error message as normal data.
Streams describe intent. stdout means “this is the command’s normal result”; stderr means “this is diagnostic information.” Whether either stream appears on screen, enters a file, or travels through a pipe is a separate connection decision.
Redirect Standard Output with > and >>
The shell interprets redirection operators before the selected command runs. The command normally receives an already-connected output stream; it does not need to parse the > symbol itself.
printf '%s\n' 'first line' > report.txt
> connects stdout to report.txt. If the file does not exist, the shell creates it. If it already exists, ordinary Bash output redirection opens it in a way that truncates its previous contents unless a protective shell option changes that behavior.
printf '%s\n' 'another line' >> report.txt
>> opens the destination for appending, so new output is written after the existing contents.
Do not experiment with > against an important configuration, key, database, or log file. Redirection is prepared before the command executes, so an existing file can be emptied even if the command later fails to produce useful output.
Redirect Standard Input with <
The opposite operator connects a file to a command’s stdin:
wc -l < report.txt
The wc program reads data from standard input and counts lines. Because the shell opened report.txt as stdin, wc does not need the filename as an argument.
Compare that with:
wc -l report.txt
Both forms can count the file’s lines, but they are not identical interfaces. In the second form, wc receives a filename argument and commonly includes that filename in its output. In the redirected form, it reads an unnamed stream.
Redirect stderr with File Descriptor 2
Because > without a number refers to stdout, redirecting diagnostics requires the descriptor for stderr:
some-command > normal-output.txt 2> errors.txt
This connects file descriptor 1 to one file and file descriptor 2 to another. The command name is illustrative; use a real command appropriate to your task.
| Operator | Connection | Important behavior |
|---|---|---|
> file |
stdout to a file | Creates or normally truncates the destination. |
>> file |
stdout to a file | Appends instead of replacing existing contents. |
< file |
File to stdin | The command reads the file as its standard input. |
2> file |
stderr to a file | Normal stdout keeps its existing destination. |
2>&1 |
stderr to stdout’s current destination | Duplicates the connection that stdout has at that point. |
| |
stdout of the left command to stdin of the right | stderr is not included by the ordinary pipe operator. |
The GNU Bash redirection reference documents the complete syntax and behavior.
Why Redirection Order Matters
Bash processes redirections from left to right. Consider these two commands:
command > combined.log 2>&1
command 2>&1 > stdout.log
In the first line, stdout is connected to combined.log, then stderr is connected to stdout’s current destination. Both streams therefore reach the file.
In the second line, stderr is first connected to wherever stdout points at that moment—commonly the terminal. stdout is then moved to stdout.log, but stderr keeps its earlier connection. Only normal output reaches the file.
2>&1 does not mean “send errors to a file named 1.” It means “make descriptor 2 refer to the current destination of descriptor 1.”
🔗 What a Pipe Actually Connects
A pipeline joins commands directly:
printf '%s\n' 'alpha' 'beta' | wc -l
The shell creates a pipe, connects the left command’s stdout to its write end, and connects the right command’s stdin to its read end. The terminal normally displays only the final command’s stdout.
An ordinary | does not send the left command’s stderr through the pipe. Diagnostics can still appear in the terminal while normal output is processed downstream. Bash also supports |&, which connects both stdout and stderr from the left command, but combining them should be a deliberate choice because it mixes normal data with diagnostics.
The commands in a pipeline can run at the same time. The downstream command can begin reading before the producer has finished writing, so a pipe is a live connection rather than a temporary text file.
The pipeline’s status is normally the status of its final command in Bash. The optional pipefail setting changes that rule. Scripts that make decisions from pipeline status need an explicit error-handling policy rather than assuming every failure on the left automatically becomes the final result.
See the GNU Bash pipeline reference for the exact status and execution rules.
🧪 Mini Lab: Follow Data Through the Streams
This Bash lab creates a new temporary directory, writes only inside it, and requires no administrator privileges. Run every command in the same shell so the variable continues to identify the directory.
1. Create an isolated workspace
SA_STREAM_LAB=$(mktemp -d)
printf '%s\n' "$SA_STREAM_LAB"
What to observe: mktemp -d prints the path of a newly created temporary directory. The shell stores that path in SA_STREAM_LAB.
2. Redirect stdout into a file
printf '%s\n' 'alpha' 'beta' > "$SA_STREAM_LAB/words.txt"
cat "$SA_STREAM_LAB/words.txt"
What to observe: The first command prints nothing to the terminal because stdout goes to the file. The second command reads the file and writes its contents to its own stdout.
3. Append one more line
printf '%s\n' 'gamma' >> "$SA_STREAM_LAB/words.txt"
wc -l < "$SA_STREAM_LAB/words.txt"
Expected result: The count should be 3. Input redirection makes the file the standard input of wc.
4. Separate normal output from an error
ls "$SA_STREAM_LAB/missing" \
> "$SA_STREAM_LAB/stdout.txt" \
2> "$SA_STREAM_LAB/stderr.txt"
wc -c < "$SA_STREAM_LAB/stdout.txt"
wc -c < "$SA_STREAM_LAB/stderr.txt"
What to observe: The stdout file should be empty, while the stderr file should contain a diagnostic. Its exact wording and byte count can vary, so compare empty versus non-empty rather than expecting a fixed number.
5. Build a simple pipeline
printf '%s\n' 'alpha' 'beta' |
tr '[:lower:]' '[:upper:]' |
wc -l
How to interpret it: printf produces two lines, tr transforms their letters, and wc counts the lines. Each stage receives the previous stage’s stdout as stdin.
6. Inspect and remove the temporary workspace
First print the target and list its contents:
printf 'temporary directory: %s\n' "$SA_STREAM_LAB"
ls -la "$SA_STREAM_LAB"
Run the cleanup only if the printed value is the temporary directory created in step 1. The command recursively removes that directory and its practice files.
rm -r -- "$SA_STREAM_LAB"
unset SA_STREAM_LAB
Result: You have observed overwrite, append, input redirection, separate stdout and stderr, and a three-command pipeline.
⚠️ Common Stream and Pipeline Mistakes
stdout and stderr commonly share the terminal by default, so they can look identical. Redirect them separately to determine which stream a command uses.
The ordinary pipe operator connects stdout only. stderr retains its own destination unless you redirect or explicitly combine it.
> normally replaces the destination’s previous contents, while >> appends. Confusing them can destroy data or cause files to grow indefinitely.
It duplicates stdout’s destination at the moment Bash processes that operator. A later stdout redirection does not automatically move stderr again.
Bash normally reports the final command’s status for a pipeline. Earlier stages can fail without becoming the pipeline’s final status unless your shell policy accounts for them.
Short Summary
stdin, stdout, and stderr are standard process connections identified by descriptors 0, 1, and 2. Their common terminal destinations are defaults, not fixed properties.
Redirection reconnects a stream to a file or another destination. A pipe connects one command’s stdout to the next command’s stdin. Once you identify the stream and follow the connection from left to right, complex command lines become much easier to reason about.
- What roles do stdin, stdout, and stderr play, and which file descriptor belongs to each?
- Why can stdout and stderr look like one stream during an interactive session?
- What practical difference separates
>from>>? - What connection does the ordinary pipe operator create?
- Why do
>file 2>&1and2>&1 >filebehave differently? - Why can a pipeline appear successful even if an earlier command failed?
🎓 Check Your Answers
- stdin, descriptor 0, supplies input. stdout, descriptor 1, carries normal results. stderr, descriptor 2, carries diagnostics and errors. The shell can reconnect each descriptor independently.
- Both streams commonly point to the same terminal by default. Their text appears in one place even though the process writes through two separate descriptors.
>creates or normally truncates the destination before writing.>>preserves existing contents and appends new output at the end.- An ordinary pipe connects stdout of the command on its left to stdin of the command on its right. It does not include stderr unless that stream is explicitly combined or redirected.
- Bash processes redirections from left to right.
2>&1copies stdout’s destination as it exists at that point, so changing stdout afterward does not retroactively change stderr. - Bash normally uses the final command’s exit status as the pipeline status. An earlier failure may therefore be hidden unless the script inspects stages or enables an appropriate option such as
pipefail.
Commands do not inherently read from keyboards or write to screens. They read and write streams, while the shell decides where those streams connect.
To understand a command line, follow the data: identify stdin, stdout, and stderr; apply redirections from left to right; then trace each pipe from producer to consumer.








