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