## 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:

    $ 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:

    $ 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 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. 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, which 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.

Filename: src/main.rs

    use std::env;

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

Listing 12-1: Collecting the command line arguments into a vector and printing them

First, we bring the `std::env` module into scope with a `use` statement so that 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, 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:

    $ cargo run
       Compiling minigrep v0.1.0 (file:///projects/minigrep)
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.61s
         Running `target/debug/minigrep`
    [src/main.rs:5:5] args = [
        "target/debug/minigrep",
    ]

    $ cargo run -- needle haystack
       Compiling minigrep v0.1.0 (file:///projects/minigrep)
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.57s
         Running `target/debug/minigrep needle haystack`
    [src/main.rs:5:5] args = [
        "target/debug/minigrep",
        "needle",
        "haystack",
    ]

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 that we can use the values throughout the rest of the program. We do that in Listing 12-2.

Filename: src/main.rs

    use std::env;

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

        let query = &args[1];
        let file_path = &args[2];

        println!("Searching for {query}");
        println!("In file {file_path}");
    }

Listing 12-2: Creating variables to hold the query argument and file path argument

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`:

    $ cargo run -- test sample.txt
       Compiling minigrep v0.1.0 (file:///projects/minigrep)
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.0s
         Running `target/debug/minigrep test sample.txt`
    Searching for test
    In file sample.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.