]>
Commit | Line | Data |
---|---|---|
3b2f2976 | 1 | ## Writing Error Messages to Standard Error Instead of Standard Output |
041b39d2 | 2 | |
ff7c6d11 | 3 | At the moment we’re writing all of our output to the terminal using the |
3b2f2976 | 4 | `println!` function. Most terminals provide two kinds of output: *standard |
2c00a5a8 | 5 | output* (`stdout`) for general information and *standard error* (`stderr`) |
ff7c6d11 XL |
6 | for error messages. This distinction enables users to choose to direct the |
7 | successful output of a program to a file but still print error messages to the | |
8 | screen. | |
041b39d2 | 9 | |
ff7c6d11 XL |
10 | The `println!` function is only capable of printing to standard output, so we |
11 | have to use something else to print to standard error. | |
041b39d2 | 12 | |
ff7c6d11 | 13 | ### Checking Where Errors Are Written to |
041b39d2 | 14 | |
ff7c6d11 XL |
15 | First, let’s observe how the content printed by `minigrep` is currently being |
16 | written to standard output, including any error messages we want to write to | |
041b39d2 | 17 | standard error instead. We’ll do that by redirecting the standard output stream |
ff7c6d11 | 18 | to a file while also intentionally causing an error. We won’t redirect the |
041b39d2 | 19 | standard error stream, so any content sent to standard error will continue to |
ff7c6d11 XL |
20 | display on the screen. |
21 | ||
22 | Command line programs are expected to send error messages to the standard error | |
23 | stream so we can still see error messages on the screen even if we redirect the | |
24 | standard output stream to a file. Our program is not currently well-behaved: | |
25 | we’re about to see that it saves the error message output to a file instead! | |
041b39d2 XL |
26 | |
27 | The way to demonstrate this behavior is by running the program with `>` and the | |
28 | filename, *output.txt*, that we want to redirect the standard output stream to. | |
ff7c6d11 | 29 | We won’t pass any arguments, which should cause an error: |
cc61c64b XL |
30 | |
31 | ```text | |
32 | $ cargo run > output.txt | |
33 | ``` | |
34 | ||
3b2f2976 | 35 | The `>` syntax tells the shell to write the contents of standard output to |
041b39d2 | 36 | *output.txt* instead of the screen. We didn’t see the error message we were |
cc61c64b | 37 | expecting printed on the screen, so that means it must have ended up in the |
ff7c6d11 | 38 | file. This is what *output.txt* contains: |
cc61c64b XL |
39 | |
40 | ```text | |
7cac9316 | 41 | Problem parsing arguments: not enough arguments |
cc61c64b XL |
42 | ``` |
43 | ||
3b2f2976 | 44 | Yup, our error message is being printed to standard output. It’s much more |
ff7c6d11 | 45 | useful for error messages like this to be printed to standard error and have |
3b2f2976 | 46 | only data from a successful run end up in the file when we redirect standard |
ff7c6d11 | 47 | output this way. We’ll change that. |
cc61c64b | 48 | |
041b39d2 | 49 | ### Printing Errors to Standard Error |
cc61c64b | 50 | |
ff7c6d11 | 51 | We’ll use the code in Listing 12-24 to change how error messages are printed. |
041b39d2 | 52 | Because of the refactoring we did earlier in this chapter, all the code that |
ff7c6d11 XL |
53 | prints error messages is in one function, `main`. The standard library provides |
54 | the `eprintln!` macro that prints to the standard error stream, so let’s change | |
55 | the two places we were calling `println!` to print errors to use `eprintln!` | |
56 | instead: | |
cc61c64b | 57 | |
041b39d2 | 58 | <span class="filename">Filename: src/main.rs</span> |
cc61c64b | 59 | |
041b39d2 | 60 | ```rust,ignore |
cc61c64b XL |
61 | fn main() { |
62 | let args: Vec<String> = env::args().collect(); | |
cc61c64b XL |
63 | |
64 | let config = Config::new(&args).unwrap_or_else(|err| { | |
041b39d2 | 65 | eprintln!("Problem parsing arguments: {}", err); |
cc61c64b XL |
66 | process::exit(1); |
67 | }); | |
68 | ||
041b39d2 XL |
69 | if let Err(e) = minigrep::run(config) { |
70 | eprintln!("Application error: {}", e); | |
cc61c64b XL |
71 | |
72 | process::exit(1); | |
73 | } | |
74 | } | |
75 | ``` | |
76 | ||
3b2f2976 XL |
77 | <span class="caption">Listing 12-24: Writing error messages to standard error |
78 | instead of standard output using `eprintln!`</span> | |
cc61c64b | 79 | |
ff7c6d11 XL |
80 | After changing `println!` to `eprintln!`, let’s run the program again in the |
81 | same way, without any arguments and redirecting standard output with `>`: | |
cc61c64b XL |
82 | |
83 | ```text | |
84 | $ cargo run > output.txt | |
7cac9316 | 85 | Problem parsing arguments: not enough arguments |
cc61c64b XL |
86 | ``` |
87 | ||
ff7c6d11 XL |
88 | Now we see the error onscreen and *output.txt* contains nothing, which is the |
89 | behavior we expect of command line programs. | |
cc61c64b | 90 | |
ff7c6d11 XL |
91 | Let’s run the program again with arguments that don’t cause an error but still |
92 | redirect standard output to a file, like so: | |
cc61c64b XL |
93 | |
94 | ```text | |
95 | $ cargo run to poem.txt > output.txt | |
96 | ``` | |
97 | ||
ff7c6d11 | 98 | We won’t see any output to the terminal, and *output.txt* will contain our |
cc61c64b XL |
99 | results: |
100 | ||
101 | <span class="filename">Filename: output.txt</span> | |
102 | ||
103 | ```text | |
104 | Are you nobody, too? | |
105 | How dreary to be somebody! | |
106 | ``` | |
107 | ||
ff7c6d11 XL |
108 | This demonstrates that we’re now using standard output for successful output |
109 | and standard error for error output as appropriate. | |
cc61c64b XL |
110 | |
111 | ## Summary | |
112 | ||
ff7c6d11 XL |
113 | In this chapter, we’ve recapped some of the major concepts you’ve learned so |
114 | far and covered how to do common I/O operations in a Rust context. By using | |
115 | command line arguments, files, environment variables, and the `eprintln!` macro | |
116 | for printing errors, you’re now prepared to write command line applications. By | |
117 | using the concepts in previous chapters, your code will be well organized, | |
118 | store data effectively in the appropriate data structures, handle errors | |
119 | nicely, and be well tested. | |
120 | ||
121 | Next, we’ll explore some Rust features that were influenced by functional | |
122 | languages: closures and iterators. |