Learning Rust Pt. 2 — Command Line Arguments

Matthew Seyer
3 min readDec 22, 2016

--

Today we are looking at how to parse command line arguments! Something most tools will need to do, unless you get crazy and like to design GUI’s for everything. Either way, its one component I know I will need in most of my projects.

Couple notes to the readers. I want these blogs to be more of a reference, because they are differently not a how to guide. I am not teaching you all the components of Rust, such as how to declare a String or an unsigned integer. This is what books and documentation are for, and I would highly recommend the Rust Essentials book. It has got me this far and its smaller than any C, C++, or Java book I have seen. Its a great plane book and a very easy read.

I know not everyone will be reading this with intent to try and make a DFIR tool in Rust. At the very least, maybe by skimming through it you will see its not much harder than something like Python and peak your interest.

Lets talk IDE real quick. Getting started in Rust I kept looking for a decent IDE to help me out. For Python I have always liked Komodo IDE, and for personal use I stick with PyCharm. Both are great. Both you can debug in. Debugging with break points is something I have come to rely on. It is always helpful to see inside my structures and objects when I get stuck. Unfortunately I have yet to find an IDE that I can use break points and view structures in for Rust, nor do I believe it exists. You win some you lose some.

For Rust my IDE of choice has come to Atom. Its pretty and its cross platform which is nice. Not only that, but combined with racer, Atom can give us Rust code completion. This is a major time saver! Want to set it up? Here is the documentation on how to do so: https://github.com/edubkendo/atom-racer. Better to use that than rely on me showing you.

Now, lets dive into some code! In part 1 we talked about Cargo and how it makes using libraries insanely easy. Now its time to use a library for parsing command line arguments. I am using my code from my RustyUsn project as examples for this series. Lets look at the main component called main.rs (I am just going to dump the code here because it is not long and is subject to change very soon).

mod usnpkg;
extern crate clap;
use clap::{App, Arg};
fn main() {
let options = App::new("MyUsnApp")
.version("1.0")
.author("Matthew Seyer <
matthew.seyer@gmail.com>")
.about("Parse USN records")
.arg(Arg::with_name("journal")
.short("j")
.long("journal")
.value_name("FILE")
.help("The USN journal file to parse")
.takes_value(true)
.required(true))
.get_matches();
// output journal name
if let Some(journal_name) = options.value_of("journal") {
println!(
"Journal to parse: {}",
journal_name
);
}
// get usn_connection from a filename
let mut usn_connection = usnpkg::usn::open_file(
options.value_of("journal").unwrap()
);
let mut cnt = 1;
while let Ok(record) = usn_connection.get_next_record(){
println!("USN structure {}: {:#?}",cnt,record);
cnt += 1;
};
}

Everything we are concerned with today I have marked in bold. All we want to do is say we want to use an external crate (library) named clap [extern crate clap;] . clap is the command line argument parsing library we want to use. Then we want to import the modules that we are going to use from it with [use clap::{App, Arg};]. After that its all about reading the documentation for the module itself.

let options = App::new("MyUsnApp")
.version("1.0")
.author("Matthew Seyer <
matthew.seyer@gmail.com>")
.about("Parse USN records")
.arg(Arg::with_name("journal")
.short("j")
.long("journal")
.value_name("FILE")
.help("The USN journal file to parse")
.takes_value(true)
.required(true))
.get_matches();

Not much I feel I need to say because the code kinda speaks for itself. It is as easy as using Python’s argparse. Or, if you have lots of arguments you could even create variables for each argument:

let arg_journal = Arg::with_name("journal")
.short("j")
.long("journal")
.value_name("FILE")
.help("The USN journal file to parse")
.takes_value(true)
.required(true);
let options = App::new("MyUsnApp")
.version("1.0")
.author("Matthew Seyer <matthew.seyer@gmail.com>")
.about("Parse USN records")
.arg(arg_journal)
.get_matches();

To get the value all we have to do is use:

options.value_of("journal").unwrap()

options.value_of() function gives us an Option enumeration. Meaning it will have a value or will be Null. The unwrap() will give us the value of the Some(). You either have Some() or you have None.

This piece of code here will check if journal_name is indeed a value, if it is a value, it will print the value. But it should always be something because for the arg_journal we told it .required(true).

if let Some(journal_name) = options.value_of("journal") {
println!(
"Journal to parse: {}",
journal_name
);
}

That’s it. As you can see, dealing with command line arguments in Rust is very simple.

--

--