DSK-21Recommended
Write results to stdout and everything else to stderr
Write only the command's result to standard output. Progress, warnings, prompts and errors go to standard error. Colour and spinners appear only when the stream is a terminal and NO_COLOR is unset.
How to do it
A pipe such as invoices list | wc -l breaks when a progress line lands in the result. POSIX says standard error is for diagnostic messages. Check whether each stream is a terminal before you add colour, progress bars or tables made for the eye. Honour the NO_COLOR environment variable, which many tools read. A --quiet flag silences standard error except for errors. Machine-readable output follows offer JSON output with a stable shape.
Examples
Python example
import os, sys
use_colour = sys.stderr.isatty() and "NO_COLOR" not in os.environ
def warn(message: str) -> None:
print(f"\033[33m{message}\033[0m" if use_colour else message, file=sys.stderr)
for invoice in invoices:
warn(f"exporting {invoice.number}") if not args.quiet else None
print(invoice.to_csv_row())
Go example
func warn(message string) {
if term.IsTerminal(int(os.Stderr.Fd())) && os.Getenv("NO_COLOR") == "" {
message = "\033[33m" + message + "\033[0m"
}
fmt.Fprintln(os.Stderr, message)
}
for _, invoice := range invoices {
warn("exporting " + invoice.Number)
fmt.Println(invoice.CSVRow())
}
How to check
A test runs each command with standard output sent to a file and standard error to another. The output file holds only the result, with no escape codes. With NO_COLOR=1 set, standard error holds no escape codes either.
Sources
Related rules
- DSK-22 Offer JSON output with a stable shape in Desktop apps, extensions and CLIs
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/desktop-apps/command-line-tools/stdout-stderr">Agent Wranglers desktop apps, extensions and CLIs playbook</a>. In code you write, add a comment next to it with the same link.