Files
docs-rust/ch12/ch12-01-accepting-command-line-arguments.html
2026-06-22 21:27:36 +05:30

143 lines
8.4 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Accepting Command Line Arguments</title>
</head>
<body>
<h2 id="accepting-command-line-arguments"><a class="header" href="#accepting-command-line-arguments">Accepting Command Line Arguments</a></h2>
<p>Lets create a new project with, as always, <code>cargo new</code>. Well call our project
<code>minigrep</code> to distinguish it from the <code>grep</code> tool that you might already have
on your system:</p>
<pre><code class="language-console">$ cargo new minigrep
Created binary (application) `minigrep` project
$ cd minigrep
</code></pre>
<p>The first task is to make <code>minigrep</code> 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 <code>cargo run</code>, two hyphens to indicate the following arguments are
for our program rather than for <code>cargo</code>, a string to search for, and a path to
a file to search in, like so:</p>
<pre><code class="language-console">$ cargo run -- searchstring example-filename.txt
</code></pre>
<p>Right now, the program generated by <code>cargo new</code> cannot process arguments we
give it. Some existing libraries on <a href="https://crates.io/">crates.io</a> can help
with writing a program that accepts command line arguments, but because youre
just learning this concept, lets implement this capability ourselves.</p>
<h3 id="reading-the-argument-values"><a class="header" href="#reading-the-argument-values">Reading the Argument Values</a></h3>
<p>To enable <code>minigrep</code> to read the values of command line arguments we pass to
it, well need the <code>std::env::args</code> function provided in Rusts standard
library. This function returns an iterator of the command line arguments passed
to <code>minigrep</code>. Well cover iterators fully in <a href="../ch13/ch13-00-functional-features.html">Chapter 13</a><!-- ignore
-->. For now, you only need to know two details about iterators: Iterators
produce a series of values, and we can call the <code>collect</code> method on an iterator
to turn it into a collection, such as a vector, which contains all the elements
the iterator produces.</p>
<p>The code in Listing 12-1 allows your <code>minigrep</code> program to read any command
line arguments passed to it and then collect the values into a vector.</p>
<figure class="listing" id="listing-12-1">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">use std::env;
fn main() {
let args: Vec&lt;String&gt; = env::args().collect();
dbg!(args);
}</code></pre>
<figcaption><a href="#listing-12-1">Listing 12-1</a>: Collecting the command line arguments into a vector and printing them</figcaption>
</figure>
<p>First, we bring the <code>std::env</code> module into scope with a <code>use</code> statement so that
we can use its <code>args</code> function. Notice that the <code>std::env::args</code> function is
nested in two levels of modules. As we discussed in <a href="../ch07/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths">Chapter
7</a><!-- ignore -->, in cases where the desired function is
nested in more than one module, weve chosen to bring the parent module into
scope rather than the function. By doing so, we can easily use other functions
from <code>std::env</code>. Its also less ambiguous than adding <code>use std::env::args</code> and
then calling the function with just <code>args</code>, because <code>args</code> might easily be
mistaken for a function thats defined in the current module.</p>
<section class="note" aria-role="note">
<h3 id="the-args-function-and-invalid-unicode"><a class="header" href="#the-args-function-and-invalid-unicode">The <code>args</code> Function and Invalid Unicode</a></h3>
<p>Note that <code>std::env::args</code> will panic if any argument contains invalid
Unicode. If your program needs to accept arguments containing invalid
Unicode, use <code>std::env::args_os</code> instead. That function returns an iterator
that produces <code>OsString</code> values instead of <code>String</code> values. Weve chosen to
use <code>std::env::args</code> here for simplicity because <code>OsString</code> values differ per
platform and are more complex to work with than <code>String</code> values.</p>
</section>
<p>On the first line of <code>main</code>, we call <code>env::args</code>, and we immediately use
<code>collect</code> to turn the iterator into a vector containing all the values produced
by the iterator. We can use the <code>collect</code> function to create many kinds of
collections, so we explicitly annotate the type of <code>args</code> to specify that we
want a vector of strings. Although you very rarely need to annotate types in
Rust, <code>collect</code> is one function you do often need to annotate because Rust
isnt able to infer the kind of collection you want.</p>
<p>Finally, we print the vector using the debug macro. Lets try running the code
first with no arguments and then with two arguments:</p>
<pre><code class="language-console">$ 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",
]
</code></pre>
<pre><code class="language-console">$ 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",
]
</code></pre>
<p>Notice that the first value in the vector is <code>"target/debug/minigrep"</code>, 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.
Its 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, well ignore it and save only the two arguments we need.</p>
<h3 id="saving-the-argument-values-in-variables"><a class="header" href="#saving-the-argument-values-in-variables">Saving the Argument Values in Variables</a></h3>
<p>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.</p>
<figure class="listing" id="listing-12-2">
<span class="file-name">Filename: src/main.rs</span>
<pre><code class="language-rust should_panic noplayground">use std::env;
fn main() {
let args: Vec&lt;String&gt; = env::args().collect();
let query = &amp;args[1];
let file_path = &amp;args[2];
println!("Searching for {query}");
println!("In file {file_path}");
}</code></pre>
<figcaption><a href="#listing-12-2">Listing 12-2</a>: Creating variables to hold the query argument and file path argument</figcaption>
</figure>
<p>As we saw when we printed the vector, the programs name takes up the first
value in the vector at <code>args[0]</code>, so were starting arguments at index 1. The
first argument <code>minigrep</code> takes is the string were searching for, so we put a
reference to the first argument in the variable <code>query</code>. The second argument
will be the file path, so we put a reference to the second argument in the
variable <code>file_path</code>.</p>
<p>We temporarily print the values of these variables to prove that the code is
working as we intend. Lets run this program again with the arguments <code>test</code>
and <code>sample.txt</code>:</p>
<pre><code class="language-console">$ 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
</code></pre>
<p>Great, the program is working! The values of the arguments we need are being
saved into the right variables. Later well add some error handling to deal
with certain potential erroneous situations, such as when the user provides no
arguments; for now, well ignore that situation and work on adding file-reading
capabilities instead.</p>
</body>
</html>