Code of the Day
BeginnerUtility Thinking

Input and output

Every utility reads from somewhere and writes to somewhere. Keeping stdout and stderr separate is what makes your tool composable.

UtilitiesBeginner8 min read
Recommended first
By the end of this lesson you will be able to:
  • Print data output to stdout with print()
  • Write diagnostic messages to stderr with sys.stderr.write()
  • Read all of stdin with sys.stdin.read()
  • Explain why separating stdout and stderr matters in a pipeline

Every program has three standard streams available from the moment it starts: (standard input), (standard output), and stderr (standard error). A good utility uses all three correctly and keeps them strictly separate.

stdout is for data, stderr is for humans

This is the rule that most beginners get wrong. When your utility produces output, ask yourself: is this the result of the computation, or is it a message about the computation?

  • stdout is the data channel. Whatever you write here is what the next program in the pipeline will read. Keep it clean: no progress messages, no "Processing…", no banners. Just the data.
  • stderr is the diagnostic channel. Error messages, warnings, progress indicators, debug logs — all of this goes to stderr. Users see it in the terminal, but pipelines ignore it.

In Python: print() writes to stdout by default. To write to stderr, use sys.stderr.write() (and don't forget the newline \nwrite() won't add one automatically).

Reading from stdin

sys.stdin.read() reads everything that's piped in and returns it as a string. sys.stdin.readlines() returns a list of lines. Both block until the input stream closes (which happens automatically when the upstream program finishes, or when you press Ctrl-D in a terminal).

For many utilities, the cleanest pattern is: read all of stdin, process it, write to stdout, exit. No intermediate state, no side effects.

Try it

This block simulates all three streams. Edit it to see how each stream behaves:

Python — editable, runs in your browser

Run it. Notice that both outputs appear in the terminal here — in a real shell, 2>/dev/null would suppress the stderr message, leaving only the clean data on stdout.

When you redirect output in a shell — python mytool.py > results.txt — only stdout goes into the file. stderr still prints to the terminal. That is exactly what you want: clean data in the file, diagnostic messages visible to the operator.

Why the separation matters

Imagine a utility that prints a progress message — "Reading 1000 lines…" — to stdout. Now pipe it into wc -l. The count will be off by one (or more). The downstream tool cannot distinguish your progress message from your data, because you put both in the same stream.

Keeping stdout clean is not a style preference. It is what makes your tool trustworthy in a .

Where to go next

Next: composability — how programs chain together through pipes, and the properties that make a program composable.

Finished reading? Mark it complete to track your progress.

On this page