Programming · free software · the open webSubscribe via RSS

How Can a CLI Report Progress Without Corrupting Output?

From the earlier reference collection. Read the current software blog.

Send human-facing progress messages to standard error and keep standard output reserved for the command’s data result.

Give each stream one job

A command-line program has separate standard output and standard error streams. Treat standard output as the result channel and standard error as the status channel. If a program prints JSON records to standard output and also writes Loading feed… there, a downstream parser receives invalid JSON. Sending progress to standard error keeps the machine-readable stream intact.

For example, tool --format json > result.json can save the output while progress remains visible in the terminal. A pipeline such as tool --format json | jq '.count' can consume the result without having to strip status lines first.

Make progress useful and restrained

Progress messages should describe a meaningful phase or count: Downloaded 3 of 8 files or Parsed 20,000 rows. Avoid printing every record or emitting a new line for every tiny step. Excess chatter makes a long operation harder to follow and may slow the program when the terminal is not interactive.

For an interactive terminal, a tool may update one line with a carriage return. When standard error is redirected to a file, however, repeated in-place updates can look confusing. A simple approach is to use occasional newline-terminated updates, or detect whether the stream is a terminal and choose a quieter format for redirected logs.

Keep output modes predictable

A machine-readable mode should have a clear contract: which stream contains the document, whether it emits one object or multiple records, and what happens on failure. Do not switch to a human-readable error message on standard output just because a command failed; that can break scripts that expect JSON. Put diagnostics on standard error and return a nonzero exit status.

For example, a CSV export can print its header and data rows to standard output while warnings about skipped records go to standard error. If skipped rows affect the trustworthiness of the result, the final status code and diagnostic should make that clear.

Test the stream boundary by use

Try the command in both a terminal and a pipeline. Redirect standard output to a file, then verify that the file contains only the promised format; separately redirect standard error to inspect progress. For JSON, a parser such as python -m json.tool result.json can expose accidental status text in the result file.

The distinction is small but powerful: people get useful feedback, scripts get parseable data, and callers can decide whether to display, save, or discard each stream independently.

References

  1. Python documentation

Suggest a correction · All posts