Agent Wranglers

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

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.