Back to List

Standard Input/Output β€” stdin/stdout Redirection

Understand Python's standard input/output/error streams and learn how to use redirection and pipes in the terminal.

Intermediate
|
10min
|
Verified (2026-07)
standard input/outputstdinstdoutstderrredirectionCLI
Progress0/18 (0%)

Standard Input/Output β€” stdin/stdout Redirection

After completing this topic, you will be able to:

Explain the roles of stdin, stdout, and stderr, and connect programs' input and output using redirection (>, <) and pipes (|) in the terminal.


The Three Channels

When a program runs, the operating system automatically opens three channels:

NameDirectionPurposePython
stdin (standard input)External β†’ ProgramKeyboard inputinput(), sys.stdin
stdout (standard output)Program β†’ ExternalNormal resultsprint(), sys.stdout
stderr (standard error)Program β†’ ExternalErrors/warningssys.stderr

By default, stdin is connected to the keyboard, and stdout and stderr are connected to the screen (terminal).


print() Writes to stdout

python
# hello.py
print("μ•ˆλ…•ν•˜μ„Έμš”") # Outputs to stdout
bash
$ python hello.py
μ•ˆλ…•ν•˜μ„Έμš”

print() internally calls sys.stdout.write(). You can also use it directly:

python
import sys
sys.stdout.write("Output to stdout\n")
sys.stderr.write("Output to stderr\n")

Both lines will appear on the screen, but through different channels. This difference becomes apparent with redirection.


Redirection β€” Directing Channels to Files

You can change the direction of input and output using > and < in the terminal.

Redirecting stdout to a File (>)

bash
$ python hello.py > output.txt

Nothing will appear on the screen. The result of print() will be written to the output.txt file.

bash
$ cat output.txt
μ•ˆλ…•ν•˜μ„Έμš”

>> appends to the existing content:

bash
$ python hello.py >> output.txt # Appends to existing content

Taking stdin from a File (<)

python
# count.py
import sys
lines = sys.stdin.readlines()
print(f"Total {len(lines)} lines")
bash
$ python count.py < data.txt
Total 42 lines

The content of data.txt is fed into stdin instead of keyboard input.

Separating stderr Only

python
# process.py
import sys
print("Processing result: Success")
sys.stderr.write("Warning: Some data is missing\n")
bash
$ python process.py > result.txt 2> error.txt

> redirects only stdout, and 2> redirects only stderr. This allows you to separate results and errors into different files.


Pipes β€” Connecting Programs

| (pipe) connects the stdout of one program to the stdin of the next program:

bash
$ cat data.csv | python process.py | python report.py > final.txt
text
cat β†’ (stdout) β†’ | β†’ (stdin) β†’ process.py β†’ (stdout) β†’ | β†’ (stdin) β†’ report.py β†’ final.txt

Each program receives data from its input, processes it, and passes the result to the next. This is the core of the Unix philosophy of combining small programs to perform complex tasks.


Reading stdin Line by Line in Python

python
# upper.py β€” Converts input to uppercase
import sys
for line in sys.stdin:
print(line.strip().upper())
bash
$ echo "hello world" | python upper.py
HELLO WORLD
$ cat names.txt | python upper.py
ALICE
BOB
CHARLIE

sys.stdin is iterable. Using a for loop to read line by line is memory-efficient.


Relationship between input() and stdin

python
name = input("Name: ") # Prompt β†’ stderr? No, stdout

input() internally:

  1. Prints the prompt string to stdout
  2. Reads a line from stdin and returns it

Therefore, caution is needed when using it with pipes:

bash
$ echo "철수" | python -c "name = input(); print(f'Hello, {name}')"
Hello, 철수

The prompt is meaningless in a pipe. When creating CLI tools, it is better to read sys.stdin directly instead of using input().


Practical Usage Examples

python
# csv_filter.py β€” Outputs only rows that meet specific conditions
import sys
import csv
reader = csv.reader(sys.stdin)
header = next(reader)
print(",".join(header))
for row in reader:
if float(row[2]) > 100: # 3rd column is greater than 100
print(",".join(row))
bash
$ cat sales.csv | python csv_filter.py > filtered.csv

Using stdin/stdout eliminates the need to hardcode file names. Any file can be connected via a pipe, increasing reusability.


Pipe Chaining β€” UNIX Philosophy

bash
# Find only ERRORs in the log and sort them by frequency
$ cat server.log | grep "ERROR" | sort | uniq -c | sort -rn | head -5

Each program does only one thing well, and they are connected by pipes. Python scripts can also be part of this chain:

python
# word_count.py β€” Calculates word frequency
import sys
from collections import Counter
words = []
for line in sys.stdin:
words.extend(line.strip().split())
for word, count in Counter(words).most_common(10):
print(f"{count:>5} {word}")
bash
$ cat article.txt | python word_count.py
42 the
31 and
28 to

Outputting Progress to stderr

python
import sys
total = 1000
for i in range(total):
# Processing logic...
if i % 100 == 0:
print(f"Progress: {i}/{total}", file=sys.stderr)
print(f"Result: {i * 2}") # Actual output β†’ stdout
bash
$ python process.py > results.txt
Progress: 0/1000 ← Appears on the screen (stderr)
Progress: 100/1000
...

stdout is redirected to the results.txt file, while stderr still appears on the screen. This is a practical pattern for separating progress messages and data output.


Key Summary

SyntaxMeaning
>Redirect stdout to a file (overwrite)
>>Redirect stdout to a file (append)
<Take a file as stdin
2>Redirect stderr to a file
``
2>&1Merge stderr into stdout

/dev/null β€” Discarding Output

bash
# Discard stdout (only see errors)
$ python noisy_script.py > /dev/null
# Discard stderr (only see results)
$ python noisy_script.py 2> /dev/null
# Discard both (completely silent)
$ python noisy_script.py > /dev/null 2>&1

/dev/null is a "garbage can." It is used to suppress unnecessary output in automated scripts.

python
# The same pattern in Python
import os, sys
if os.environ.get("QUIET"):
sys.stdout = open(os.devnull, "w")


subprocess β€” Building Pipes in Python

python
import subprocess
# Execute an external command + capture stdout
result = subprocess.run(
["ls", "-la"],
capture_output=True,
text=True
)
print(result.stdout)
print(result.stderr)
# Pipe chaining
p1 = subprocess.Popen(["cat", "data.txt"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "ERROR"], stdin=p1.stdout, stdout=subprocess.PIPE)
output = p2.communicate()[0].decode()

You can programmatically connect stdin/stdout of shell commands within Python.


print() writes to stdout, and error messages go to stderr. Understanding this separation makes redirection and pipes more natural.

πŸ’¬ Questions & Comments

0 comments

You can post without signing in. Guest comments cannot be edited or deleted by their author.

0/2000

Loading...