feat: added cleanscript
This commit is contained in:
142
ch12/ch12-01-accepting-command-line-arguments.html
Normal file
142
ch12/ch12-01-accepting-command-line-arguments.html
Normal file
@@ -0,0 +1,142 @@
|
||||
<!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>Let’s create a new project with, as always, <code>cargo new</code>. We’ll 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 you’re
|
||||
just learning this concept, let’s 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, we’ll need the <code>std::env::args</code> function provided in Rust’s standard
|
||||
library. This function returns an iterator of the command line arguments passed
|
||||
to <code>minigrep</code>. We’ll 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<String> = 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, we’ve 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>. It’s 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 that’s 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. We’ve 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
|
||||
isn’t able to infer the kind of collection you want.</p>
|
||||
<p>Finally, we print the vector using the debug macro. Let’s 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.
|
||||
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.</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<String> = env::args().collect();
|
||||
|
||||
let query = &args[1];
|
||||
let file_path = &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 program’s name takes up the first
|
||||
value in the vector at <code>args[0]</code>, so we’re starting arguments at index 1. The
|
||||
first argument <code>minigrep</code> takes is the string we’re 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. Let’s 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 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.</p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user