---
title: "20.x Chapter 20 summary and quiz"
description: "Review of command-line arguments, files, the standard streams, environment variables, and the minigrep project, with an extension exercise."
url: "https://learnrust.net/chapter-20/chapter-20-summary-and-quiz/"
last_updated: "2026-06-13"
---

# 20.x Chapter 20 summary and quiz

This chapter turned your programs outward, into tools that read the world and compose with other programs. Review, then one more extension to `minigrep`.

## Quick review

A program reads the words after its name with **`std::env::args`** ([20.1](https://learnrust.net/chapter-20/command-line-arguments/)), collected into a `Vec<String>`; index 0 is the program name, real arguments start at 1, and every argument arrives as text (use `parse` for numbers). Check the count before indexing, or `[]` panics.

Files come in two layers ([20.2](https://learnrust.net/chapter-20/reading-and-writing-files/)): **`fs::read_to_string`** and **`fs::write`** for whole files that fit in memory (both return `Result`), and **`File`** with **`BufReader`**/**`BufWriter`** for big files processed a piece at a time. Buffered writes must be **flushed**; an early `exit` before flushing loses them, the chapter-7 truncation warning made concrete.

Every program has three **standard streams** ([20.3](https://learnrust.net/chapter-20/stdin-stdout-stderr/)): stdin (input, `io::stdin`), stdout (results, `println!`), and stderr (diagnostics, `eprintln!`). Results go to stdout and everything else to stderr so output stays clean when piped or redirected. The **exit code** (0 success, non-zero failure) is set automatically by returning `Result` from `main`, which also prints errors to stderr.

**Environment variables** ([20.4](https://learnrust.net/chapter-20/environment-variables/)) configure persistent behavior and secrets, read with **`env::var`** (returns `Result`; pair with `unwrap_or_else` for a default or `is_ok` for a present/absent flag). Arguments are for per-run inputs; env vars are for set-once configuration.

The **`minigrep`** project ([20.5](https://learnrust.net/chapter-20/text-search-tool-part-1/), [20.6](https://learnrust.net/chapter-20/text-search-tool-part-2/)) assembled it all: arguments into a `Config` (with a `build` that returns `Result`), a thin `main.rs` over a `lib.rs` of logic (chapter 13), a `search` function written test-first (chapter 14), a case-insensitive mode from an environment variable, errors propagated with `?` and `Box<dyn Error>` (chapter 12), and an iterator refactor (chapter 19).

## Quiz time

**Question #1**

A program is run as `./tool --verbose input.txt`. What does `env::args().collect::<Vec<String>>()` contain, element by element?

<details class="solution">
<summary>Show solution</summary>

`["./tool", "--verbose", "input.txt"]`. Index 0 is the program's invocation name/path, index 1 is `"--verbose"`, index 2 is `"input.txt"`. All three are `String`s. Your real arguments are indices 1 and 2; interpreting `--verbose` as a flag and `input.txt` as a filename is your code's job.

</details>

**Question #2**

Why send results to stdout but errors to stderr? Give a concrete consequence of getting it wrong.

<details class="solution">
<summary>Show solution</summary>

So that redirecting or piping stdout captures only the real results while diagnostics still reach the terminal. Concrete failure: if a tool prints "Processing..." to stdout and a user runs `tool > out.txt`, that status line lands in `out.txt` and corrupts the data. Putting diagnostics on stderr (`eprintln!`) keeps `out.txt` clean while the message still shows on screen.

</details>

**Question #3**

In `minigrep`, the logic lives in `lib.rs` and `main.rs` is thin. Name two things that *stayed* in `main.rs` and explain why they belong there rather than in the library.

<details class="solution">
<summary>Show solution</summary>

Reading the real command-line arguments (`env::args().collect()`) and the error-reporting glue that calls `process::exit` (and `eprintln!`). These belong in `main.rs` because they're the hard-to-test interaction with the outside world, the actual process environment and termination, whereas everything testable (`Config::build`, `search`, `run`) lives in `lib.rs` where tests can call it directly (chapters 13 and 14).

</details>

## Chapter extension

Extend `minigrep`: make it count matches and report the total to stderr, while still printing the matching lines to stdout. Running `cargo run -- nobody poem.txt` should print the two matching lines on stdout and a line like `2 matches` on stderr.

<details class="solution">
<summary>Show solution</summary>

Modify `run` in `src/lib.rs` to collect the results, print each match to stdout, then report the count to stderr:

```rust
pub fn run(config: &Config) -> Result<(), Box<dyn Error>> {
    let contents = fs::read_to_string(&config.file_path)?;

    let results = if config.ignore_case {
        search_case_insensitive(&config.query, &contents)
    } else {
        search(&config.query, &contents)
    };

    for line in &results {
        println!("{line}");          // matches -> stdout
    }
    eprintln!("{} matches", results.len());   // summary -> stderr

    Ok(())
}
```

```bash
$ cargo run -- nobody poem.txt
I'm nobody! Who are you?
Are you nobody, too?
2 matches
```

Running `cargo run -- nobody poem.txt > out.txt` puts only the two matching lines in `out.txt`, while `2 matches` still appears in the terminal, the stdout/stderr separation (lesson 20.3) doing its job: the data is on stdout, the summary diagnostic on stderr. Borrowing `&results` in the loop lets `results.len()` still work afterward (chapter 9). This is exactly how a real tool reports a summary without polluting its output.

</details>

You can now write programs that read arguments, files, input, and configuration, and behave like first-class command-line citizens. That closes the "core Rust" arc of the course. Chapter 21 begins the advanced material with smart pointers, the types that let you reach for the heap deliberately, build recursive data structures, and bend the ownership rules when you genuinely need to, starting with the `Box` you've seen named in passing since chapter 12.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
