Writing Error Messages to `stderr` Instead of `stdout` - The Rust Programming Language

## Writing Error Messages to `stderr` Instead of `stdout`

At the moment we’re writing all of our output to the terminal with the `println!` function. Most terminals provide two kinds of output: standard out for general information, and standard error for error messages. This distinction enables users to choose whether to direct a the successful output of a program to a file but still print error messages to the screen.

The `println!` function is only capable of printing to standard out, though, so we have to use something else in order to print to standard error.

### Checking Where Errors are Written to

First, let’s observe how all content printed by `minigrep` is currently being written to standard out, including error messages that we want to write to standard error instead. We’ll do that by redirecting the standard output stream to a file while we also intentionally cause an error. We won't redirect the standard error stream, so any content sent to standard error will continue to display on the screen. Command line programs are expected to send error messages to the standard error stream so that we can still see error messages on the screen even if we choose to redirect the standard output stream to a file. Our program is not currently well-behaved; we're about to see that it saves the error message output to the file instead!

The way to demonstrate this behavior is by running the program with `>` and the filename, output.txt, that we want to redirect the standard output stream to. We're not going to pass any arguments, which should cause an error:

    $ cargo run > output.txt

The `>` syntax tells the shell to write the contents of standard out to output.txt instead of the screen. We didn’t see the error message we were expecting printed on the screen, so that means it must have ended up in the file. Let’s see what output.txt contains:

    Problem parsing arguments: not enough arguments

Yup, our error message is being printed to standard out. It’s much more useful for error messages like this to be printed to standard error, and have only data from a successful run end up in the file when we redirect standard out in this way. We’ll change that.

### Printing Errors to Standard Error

Let’s change how error messages are printed using the code in Listing 12-24. Because of the refactoring we did earlier in this chapter, all the code that prints error messages is in one function, in `main`. The standard library provides the `eprintln!` macro that prints to the standard error stream, so let's change the two places we were calling `println!` to print errors so that these spots use `eprintln!` instead:

Filename: src/main.rs

    fn main() {
        let args: Vec<String> = env::args().collect();

        let config = Config::new(&args).unwrap_or_else(|err| {
            eprintln!("Problem parsing arguments: {}", err);
            process::exit(1);
        });

        if let Err(e) = minigrep::run(config) {
            eprintln!("Application error: {}", e);

            process::exit(1);
        }
    }

Listing 12-24: Writing error messages to `stderr` instead of `stdout` using `eprintln!`

After changing `println!` to `eprintln!`, let’s try running the program again in the same way, without any arguments and redirecting `stdout` with `>`:

    $ cargo run > output.txt
    Problem parsing arguments: not enough arguments

Now we see our error on the screen and `output.txt` contains nothing, which is the behavior expected of command line programs.

If we run the program again with arguments that don’t cause an error, but still redirect standard out to a file:

    $ cargo run to poem.txt > output.txt

We won’t see any output to our terminal, and `output.txt` will contain our results:

Filename: output.txt

    Are you nobody, too?
    How dreary to be somebody!

This demonstrates that we’re now using `stdout` for successful output and `stderr` for error output as appropriate.

## Summary

In this chapter, we’ve recapped on some of the major concepts so far and covered how to do common I/O operations in a Rust context. By using command line arguments, files, environment variables, and the `eprintln!` macro with `stderr`, you’re now prepared to write command line applications. By using the concepts from previous chapters, your code will be well-organized, be able to store data effectively in the appropriate data structures, handle errors nicely, and be well tested.

Next, let’s explore some functional-language influenced Rust features: closures and iterators.