]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Accepting Command Line Arguments |
2 | ||
3 | Let’s create a new project with, as always, `cargo new`. We’ll call our project | |
4 | `minigrep` to distinguish it from the `grep` tool that you might already have | |
5 | on your system. | |
6 | ||
f035d41b | 7 | ```console |
13cf67c4 XL |
8 | $ cargo new minigrep |
9 | Created binary (application) `minigrep` project | |
10 | $ cd minigrep | |
11 | ``` | |
12 | ||
13 | The first task is to make `minigrep` accept its two command line arguments: the | |
923072b8 FG |
14 | file path and a string to search for. That is, we want to be able to run our |
15 | program with `cargo run`, two hyphens to indicate the following arguments are | |
16 | for our program rather than for `cargo`, a string to search for, and a path to | |
17 | a file to search in, like so: | |
13cf67c4 | 18 | |
f035d41b | 19 | ```console |
923072b8 | 20 | $ cargo run -- searchstring example-filename.txt |
13cf67c4 XL |
21 | ``` |
22 | ||
23 | Right now, the program generated by `cargo new` cannot process arguments we | |
dc9dc135 | 24 | give it. Some existing libraries on [crates.io](https://crates.io/) can help |
13cf67c4 XL |
25 | with writing a program that accepts command line arguments, but because you’re |
26 | just learning this concept, let’s implement this capability ourselves. | |
27 | ||
28 | ### Reading the Argument Values | |
29 | ||
30 | To enable `minigrep` to read the values of command line arguments we pass to | |
04454e1e FG |
31 | it, we’ll need the `std::env::args` function provided in Rust’s standard |
32 | library. This function returns an iterator of the command line arguments passed | |
33 | to `minigrep`. We’ll cover iterators fully in [Chapter 13][ch13]<!-- ignore | |
34 | -->. For now, you only need to know two details about iterators: iterators | |
35 | produce a series of values, and we can call the `collect` method on an iterator | |
36 | to turn it into a collection, such as a vector, that contains all the elements | |
37 | the iterator produces. | |
13cf67c4 | 38 | |
04454e1e FG |
39 | The code in Listing 12-1 allows your `minigrep` program to read any command |
40 | line arguments passed to it and then collect the values into a vector. | |
13cf67c4 XL |
41 | |
42 | <span class="filename">Filename: src/main.rs</span> | |
43 | ||
44 | ```rust | |
74b04a01 | 45 | {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-01/src/main.rs}} |
13cf67c4 XL |
46 | ``` |
47 | ||
48 | <span class="caption">Listing 12-1: Collecting the command line arguments into | |
49 | a vector and printing them</span> | |
50 | ||
51 | First, we bring the `std::env` module into scope with a `use` statement so we | |
52 | can use its `args` function. Notice that the `std::env::args` function is | |
48663c56 XL |
53 | nested in two levels of modules. As we discussed in [Chapter |
54 | 7][ch7-idiomatic-use]<!-- ignore -->, in cases where the desired function is | |
923072b8 FG |
55 | nested in more than one module, we’ve chosen to bring the parent module into |
56 | scope rather than the function. By doing so, we can easily use other functions | |
57 | from `std::env`. It’s also less ambiguous than adding `use std::env::args` and | |
58 | then calling the function with just `args`, because `args` might easily be | |
59 | mistaken for a function that’s defined in the current module. | |
13cf67c4 XL |
60 | |
61 | > ### The `args` Function and Invalid Unicode | |
62 | > | |
63 | > Note that `std::env::args` will panic if any argument contains invalid | |
64 | > Unicode. If your program needs to accept arguments containing invalid | |
65 | > Unicode, use `std::env::args_os` instead. That function returns an iterator | |
66 | > that produces `OsString` values instead of `String` values. We’ve chosen to | |
67 | > use `std::env::args` here for simplicity, because `OsString` values differ | |
68 | > per platform and are more complex to work with than `String` values. | |
69 | ||
70 | On the first line of `main`, we call `env::args`, and we immediately use | |
71 | `collect` to turn the iterator into a vector containing all the values produced | |
72 | by the iterator. We can use the `collect` function to create many kinds of | |
73 | collections, so we explicitly annotate the type of `args` to specify that we | |
74 | want a vector of strings. Although we very rarely need to annotate types in | |
75 | Rust, `collect` is one function you do often need to annotate because Rust | |
76 | isn’t able to infer the kind of collection you want. | |
77 | ||
923072b8 FG |
78 | Finally, we print the vector using the debug macro. Let’s try running the code |
79 | first with no arguments and then with two arguments: | |
13cf67c4 | 80 | |
f035d41b | 81 | ```console |
74b04a01 XL |
82 | {{#include ../listings/ch12-an-io-project/listing-12-01/output.txt}} |
83 | ``` | |
13cf67c4 | 84 | |
f035d41b | 85 | ```console |
74b04a01 | 86 | {{#include ../listings/ch12-an-io-project/output-only-01-with-args/output.txt}} |
13cf67c4 XL |
87 | ``` |
88 | ||
89 | Notice that the first value in the vector is `"target/debug/minigrep"`, which | |
90 | is the name of our binary. This matches the behavior of the arguments list in | |
91 | C, letting programs use the name by which they were invoked in their execution. | |
92 | It’s often convenient to have access to the program name in case you want to | |
93 | print it in messages or change behavior of the program based on what command | |
94 | line alias was used to invoke the program. But for the purposes of this | |
95 | chapter, we’ll ignore it and save only the two arguments we need. | |
96 | ||
97 | ### Saving the Argument Values in Variables | |
98 | ||
04454e1e FG |
99 | The program is currently able to access the values specified as command line |
100 | arguments. Now we need to save the values of the two arguments in variables so | |
101 | we can use the values throughout the rest of the program. We do that in Listing | |
102 | 12-2. | |
13cf67c4 XL |
103 | |
104 | <span class="filename">Filename: src/main.rs</span> | |
105 | ||
6a06907d | 106 | ```rust,should_panic,noplayground |
74b04a01 | 107 | {{#rustdoc_include ../listings/ch12-an-io-project/listing-12-02/src/main.rs}} |
13cf67c4 XL |
108 | ``` |
109 | ||
110 | <span class="caption">Listing 12-2: Creating variables to hold the query | |
923072b8 | 111 | argument and file path argument</span> |
13cf67c4 XL |
112 | |
113 | As we saw when we printed the vector, the program’s name takes up the first | |
04454e1e FG |
114 | value in the vector at `args[0]`, so we’re starting arguments at index `1`. The |
115 | first argument `minigrep` takes is the string we’re searching for, so we put a | |
13cf67c4 | 116 | reference to the first argument in the variable `query`. The second argument |
923072b8 FG |
117 | will be the file path, so we put a reference to the second argument in the |
118 | variable `file_path`. | |
13cf67c4 XL |
119 | |
120 | We temporarily print the values of these variables to prove that the code is | |
121 | working as we intend. Let’s run this program again with the arguments `test` | |
122 | and `sample.txt`: | |
123 | ||
f035d41b | 124 | ```console |
74b04a01 | 125 | {{#include ../listings/ch12-an-io-project/listing-12-02/output.txt}} |
13cf67c4 XL |
126 | ``` |
127 | ||
128 | Great, the program is working! The values of the arguments we need are being | |
129 | saved into the right variables. Later we’ll add some error handling to deal | |
130 | with certain potential erroneous situations, such as when the user provides no | |
131 | arguments; for now, we’ll ignore that situation and work on adding file-reading | |
132 | capabilities instead. | |
48663c56 XL |
133 | |
134 | [ch13]: ch13-00-functional-features.html | |
135 | [ch7-idiomatic-use]: ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths |