How to print to standard error
Short answer: eprintln! is println! writing to standard error — same format string, different
stream. Keep the program’s real output on stdout and everything else on stderr, and every pipe
(prog | grep) and redirect (prog > out.txt) receives only the real output.
From a fresh project — cargo new stderr-demo, then replace src/main.rs with each block below and
run it with cargo run. The project name doesn’t matter until the shell commands further down — the
binary is named after it.
Two streams
Section titled “Two streams”fn main() { println!("results.txt"); eprintln!("scanning directory");}results.txtscanning directoryIn a terminal both lines appear, in the order the program writes them. They are not on the same stream, though, and the shell can separate them. Drop standard error and only the data is left:
./target/debug/stderr-demo 2>/dev/nullresults.txtDrop standard output and only the diagnostics are left:
./target/debug/stderr-demo 1>/dev/nullscanning directoryThe binary takes the project’s name — with stderr-demo it sits at target/debug/stderr-demo. Run
cargo build first, or use cargo run --quiet with the same redirects.
Keeping stdout clean
Section titled “Keeping stdout clean”That split is what makes a chatty program safe to pipe. The answers go to stdout, the talking goes to stderr:
fn main() { let entries = 2; eprintln!("reading config"); println!("alpha.txt"); println!("beta.txt"); eprintln!("{entries} entries found");}Now the shell can filter the answers without filtering the talk:
./target/debug/stderr-demo | wc -l 2./target/debug/stderr-demo | grep betabeta.txtwc counted two lines because a pipe carries stdout only; the progress lines went to the terminal
instead. prog | grep pattern and prog > results.txt stay usable no matter how much the program
talks. Capture the talking rather than losing it with 2>progress.txt, then read the file when
something looks wrong. cargo run | wc -l works the same way — cargo’s own Finished and Running
lines sit on stderr, which is why they never reach the pipe.
eprint!, and no flush
Section titled “eprint!, and no flush”eprint! is the no-newline variant, and it needs no flush: standard error is unbuffered, so every
write goes straight out. Redirect it to a file and half a second in the text is already there — the
buffer that holds print! back does not exist
here. The format string is the same one every print macro takes,
inline captures included.
One failure mode: eprintln! panics if the write fails, exactly as print! does. Pipe standard
error into head and when head stops reading, the program dies with exit code 101.
Related
Section titled “Related”- How to print without a trailing newline —
print!, and the buffering behind it - How to format strings with println! and format! — the format mini-language every print macro shares
- Working with text — the rest of the chapter