]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch12-01-accepting-command-line-arguments.md
New upstream version 1.37.0+dfsg1
[rustc.git] / src / doc / book / src / ch12-01-accepting-command-line-arguments.md
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
7 ```text
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
14 filename and a string to search for. That is, we want to be able to run our
15 program with `cargo run`, a string to search for, and a path to a file to
16 search in, like so:
17
18 ```text
19 $ cargo run searchstring example-filename.txt
20 ```
21
22 Right now, the program generated by `cargo new` cannot process arguments we
23 give it. Some existing libraries on [crates.io](https://crates.io/) can help
24 with writing a program that accepts command line arguments, but because you’re
25 just learning this concept, let’s implement this capability ourselves.
26
27 ### Reading the Argument Values
28
29 To enable `minigrep` to read the values of command line arguments we pass to
30 it, we’ll need a function provided in Rust’s standard library, which is
31 `std::env::args`. This function returns an iterator of the command line
32 arguments that were given to `minigrep`. We’ll cover iterators fully in
33 [Chapter 13][ch13]<!-- ignore -->. For now, you only need to know two details
34 about iterators: iterators produce a series of values, and we can call the
35 `collect` method on an iterator to turn it into a collection, such as a vector,
36 containing all the elements the iterator produces.
37
38 Use the code in Listing 12-1 to allow your `minigrep` program to read any
39 command line arguments passed to it and then collect the values into a vector.
40
41 <span class="filename">Filename: src/main.rs</span>
42
43 ```rust
44 use std::env;
45
46 fn main() {
47 let args: Vec<String> = env::args().collect();
48 println!("{:?}", args);
49 }
50 ```
51
52 <span class="caption">Listing 12-1: Collecting the command line arguments into
53 a vector and printing them</span>
54
55 First, we bring the `std::env` module into scope with a `use` statement so we
56 can use its `args` function. Notice that the `std::env::args` function is
57 nested in two levels of modules. As we discussed in [Chapter
58 7][ch7-idiomatic-use]<!-- ignore -->, in cases where the desired function is
59 nested in more than one module, it’s conventional to bring the parent module
60 into scope rather than the function. By doing so, we can easily use other
61 functions from `std::env`. It’s also less ambiguous than adding `use
62 std::env::args` and then calling the function with just `args`, because `args`
63 might easily be mistaken for a function that’s defined in the current module.
64
65 > ### The `args` Function and Invalid Unicode
66 >
67 > Note that `std::env::args` will panic if any argument contains invalid
68 > Unicode. If your program needs to accept arguments containing invalid
69 > Unicode, use `std::env::args_os` instead. That function returns an iterator
70 > that produces `OsString` values instead of `String` values. We’ve chosen to
71 > use `std::env::args` here for simplicity, because `OsString` values differ
72 > per platform and are more complex to work with than `String` values.
73
74 On the first line of `main`, we call `env::args`, and we immediately use
75 `collect` to turn the iterator into a vector containing all the values produced
76 by the iterator. We can use the `collect` function to create many kinds of
77 collections, so we explicitly annotate the type of `args` to specify that we
78 want a vector of strings. Although we very rarely need to annotate types in
79 Rust, `collect` is one function you do often need to annotate because Rust
80 isn’t able to infer the kind of collection you want.
81
82 Finally, we print the vector using the debug formatter, `:?`. Let’s try running
83 the code first with no arguments and then with two arguments:
84
85 ```text
86 $ cargo run
87 --snip--
88 ["target/debug/minigrep"]
89
90 $ cargo run needle haystack
91 --snip--
92 ["target/debug/minigrep", "needle", "haystack"]
93 ```
94
95 Notice that the first value in the vector is `"target/debug/minigrep"`, which
96 is the name of our binary. This matches the behavior of the arguments list in
97 C, letting programs use the name by which they were invoked in their execution.
98 It’s often convenient to have access to the program name in case you want to
99 print it in messages or change behavior of the program based on what command
100 line alias was used to invoke the program. But for the purposes of this
101 chapter, we’ll ignore it and save only the two arguments we need.
102
103 ### Saving the Argument Values in Variables
104
105 Printing the value of the vector of arguments illustrated that the program is
106 able to access the values specified as command line arguments. Now we need to
107 save the values of the two arguments in variables so we can use the values
108 throughout the rest of the program. We do that in Listing 12-2.
109
110 <span class="filename">Filename: src/main.rs</span>
111
112 ```rust,should_panic
113 use std::env;
114
115 fn main() {
116 let args: Vec<String> = env::args().collect();
117
118 let query = &args[1];
119 let filename = &args[2];
120
121 println!("Searching for {}", query);
122 println!("In file {}", filename);
123 }
124 ```
125
126 <span class="caption">Listing 12-2: Creating variables to hold the query
127 argument and filename argument</span>
128
129 As we saw when we printed the vector, the program’s name takes up the first
130 value in the vector at `args[0]`, so we’re starting at index `1`. The first
131 argument `minigrep` takes is the string we’re searching for, so we put a
132 reference to the first argument in the variable `query`. The second argument
133 will be the filename, so we put a reference to the second argument in the
134 variable `filename`.
135
136 We temporarily print the values of these variables to prove that the code is
137 working as we intend. Let’s run this program again with the arguments `test`
138 and `sample.txt`:
139
140 ```text
141 $ cargo run test sample.txt
142 Compiling minigrep v0.1.0 (file:///projects/minigrep)
143 Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
144 Running `target/debug/minigrep test sample.txt`
145 Searching for test
146 In file sample.txt
147 ```
148
149 Great, the program is working! The values of the arguments we need are being
150 saved into the right variables. Later we’ll add some error handling to deal
151 with certain potential erroneous situations, such as when the user provides no
152 arguments; for now, we’ll ignore that situation and work on adding file-reading
153 capabilities instead.
154
155 [ch13]: ch13-00-functional-features.html
156 [ch7-idiomatic-use]: ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths