| ## Accepting Command Line Arguments |
| |
| Let’s create a new project with, as always, `cargo new`. We’ll call our project |
| `minigrep` to distinguish it from the `grep` tool that you might already have on |
| your system. |
| |
| ```console |
| $ cargo new minigrep |
| Created binary (application) `minigrep` project |
| $ cd minigrep |
| ``` |
| |
| The first task is to make `minigrep` accept its two command line arguments: the |
| file path and a string to search for. That is, we want to be able to run our |
| program with `cargo run`, two hyphens to indicate the following arguments are |
| for our program rather than for `cargo`, a string to search for, and a path to a |
| file to search in, like so: |
| |
| ```console |
| $ cargo run -- searchstring example-filename.txt |
| ``` |
| |
| Right now, the program generated by `cargo new` cannot process arguments we give |
| it. Some existing libraries on [crates.io](https://crates.io/) can help with |
| writing a program that accepts command line arguments, but because you’re just |
| learning this concept, let’s implement this capability ourselves. |
| |
| ### Reading the Argument Values |
| |
| To enable `minigrep` to read the values of command line arguments we pass to it, |
| we’ll need the `std::env::args` function provided in Rust’s standard library. |
| This function returns an iterator of the command line arguments passed to |
| `minigrep`. We’ll cover iterators fully in [Chapter 13][ch13]<!-- ignore |
| -->. For now, you only need to know two details about iterators: iterators |
| produce a series of values, and we can call the `collect` method on an iterator |
| to turn it into a collection, such as a vector, that contains all the elements |
| the iterator produces. |
| |
| The code in Listing 12-1 allows your `minigrep` program to read any command line |
| arguments passed to it, and then collect the values into a vector. |
| |
| <Listing number="12-1" file-name="src/main.rs" caption="Collecting the command line arguments into a vector and printing them"> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-01/src/main.rs}} |
| ``` |
| |
| </Listing> |
| |
| First we bring the `std::env` module into scope with a `use` statement so we can |
| use its `args` function. Notice that the `std::env::args` function is nested in |
| two levels of modules. As we discussed in |
| [Chapter 7][ch7-idiomatic-use]<!-- ignore -->, in cases where the desired |
| function is nested in more than one module, we’ve chosen to bring the parent |
| module into scope rather than the function. By doing so, we can easily use other |
| functions from `std::env`. It’s also less ambiguous than adding |
| `use std::env::args` and then calling the function with just `args`, because |
| `args` might easily be mistaken for a function that’s defined in the current |
| module. |
| |
| > ### The `args` Function and Invalid Unicode |
| > |
| > Note that `std::env::args` will panic if any argument contains invalid |
| > Unicode. If your program needs to accept arguments containing invalid Unicode, |
| > use `std::env::args_os` instead. That function returns an iterator that |
| > produces `OsString` values instead of `String` values. We’ve chosen to use |
| > `std::env::args` here for simplicity because `OsString` values differ per |
| > platform and are more complex to work with than `String` values. |
| |
| On the first line of `main`, we call `env::args`, and we immediately use |
| `collect` to turn the iterator into a vector containing all the values produced |
| by the iterator. We can use the `collect` function to create many kinds of |
| collections, so we explicitly annotate the type of `args` to specify that we |
| want a vector of strings. Although you very rarely need to annotate types in |
| Rust, `collect` is one function you do often need to annotate because Rust isn’t |
| able to infer the kind of collection you want. |
| |
| Finally, we print the vector using the debug macro. Let’s try running the code |
| first with no arguments and then with two arguments: |
| |
| ```console |
| {{#include ../listings/ch12-an-io-project/listing-12-01/output.txt}} |
| ``` |
| |
| ```console |
| {{#include ../listings/ch12-an-io-project/output-only-01-with-args/output.txt}} |
| ``` |
| |
| Notice that the first value in the vector is `"target/debug/minigrep"`, which is |
| the name of our binary. This matches the behavior of the arguments list in C, |
| letting programs use the name by which they were invoked in their execution. |
| It’s often convenient to have access to the program name in case you want to |
| print it in messages or change the behavior of the program based on what command |
| line alias was used to invoke the program. But for the purposes of this chapter, |
| we’ll ignore it and save only the two arguments we need. |
| |
| ### Saving the Argument Values in Variables |
| |
| The program is currently able to access the values specified as command line |
| arguments. Now we need to save the values of the two arguments in variables so |
| we can use the values throughout the rest of the program. We do that in Listing |
| 12-2. |
| |
| <Listing number="12-2" file-name="src/main.rs" caption="Creating variables to hold the query argument and file path argument"> |
| |
| ```rust,should_panic,noplayground |
| {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-02/src/main.rs}} |
| ``` |
| |
| </Listing> |
| |
| As we saw when we printed the vector, the program’s name takes up the first |
| value in the vector at `args[0]`, so we’re starting arguments at index 1. The |
| first argument `minigrep` takes is the string we’re searching for, so we put a |
| reference to the first argument in the variable `query`. The second argument |
| will be the file path, so we put a reference to the second argument in the |
| variable `file_path`. |
| |
| We temporarily print the values of these variables to prove that the code is |
| working as we intend. Let’s run this program again with the arguments `test` and |
| `sample.txt`: |
| |
| ```console |
| {{#include ../listings/ch12-an-io-project/listing-12-02/output.txt}} |
| ``` |
| |
| Great, the program is working! The values of the arguments we need are being |
| saved into the right variables. Later we’ll add some error handling to deal with |
| certain potential erroneous situations, such as when the user provides no |
| arguments; for now, we’ll ignore that situation and work on adding file-reading |
| capabilities instead. |
| |
| [ch13]: ch13-00-functional-features.html |
| [ch7-idiomatic-use]: ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths |