How can I access command line parameters in Rust?

Command LineRust

Command Line Problem Overview


The Rust tutorial does not explain how to take parameters from the command line. fn main() is only shown with an empty parameter list in all examples.

What is the correct way of accessing command line parameters from main?

Command Line Solutions


Solution 1 - Command Line

You can access the command line arguments by using the std::env::args or std::env::args_os functions. Both functions return an iterator over the arguments. The former iterates over Strings (that are easy to work with) but panics if one of the arguments is not valid unicode. The latter iterates over OsStrings and never panics.

Note that the first element of the iterator is the name of the program itself (this is a convention in all major OSes), so the first argument is actually the second iterated element.

An easy way to deal with the result of args is to convert it to a Vec:

use std::env;

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() > 1 {
        println!("The first argument is {}", args[1]);
    }
}

You can use the whole standard iterator toolbox to work with these arguments. For example, to retrieve only the first argument:

use std::env;

fn main() {
    if let Some(arg1) = env::args().nth(1) {
        println!("The first argument is {}", arg1);
    }
}

You can find libraries on crates.io for parsing command line arguments:

  • docopt: you just write the help message, and the parsing code is generated for you.
  • clap: you describe the options you want to parse using a fluent API. Faster than docopt and gives you more control.
  • getopts: port of the popular C library. Lower-level and even more control.
  • structopt: built on top of clap, it is even more ergonomic to use.

Solution 2 - Command Line

Docopt is also available for Rust, which generates a parser for you from a usage string. As a bonus in Rust, a macro can be used to automatically generate the struct and do type based decoding:

docopt!(Args, "
Usage: cp [-a] SOURCE DEST
       cp [-a] SOURCE... DIR

Options:
    -a, --archive  Copy everything.
")

And you can get the arguments with:

let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

The README and documentation have plenty of full working examples.

Disclaimer: I am one of the authors of this library.

Solution 3 - Command Line

Rust has getopt-style CLI argument parsing in the getopts crate.

Solution 4 - Command Line

For me, getopts always felt too low-level and docopt.rs was too much magic. I want something explicit and straightforward that still provides all the features if I need them.

This is where clap-rs comes in handy.
It feels a bit like argparse from Python. Here is an example of how it looks like:

let matches = App::new("myapp")
                      .version("1.0")
                      .author("Kevin K. <[email protected]>")
                      .about("Does awesome things")
                      .arg(Arg::with_name("CONFIG")
                           .short("c")
                           .long("config")
                           .help("Sets a custom config file")
                           .takes_value(true))
                      .arg(Arg::with_name("INPUT")
                           .help("Sets the input file to use")
                           .required(true)
                           .index(1))
                      .arg(Arg::with_name("debug")
                           .short("d")
                           .multiple(true)
                           .help("Sets the level of debugging information"))
                      .get_matches();

You can access your parameters like so:

println!("Using input file: {}", matches.value_of("INPUT").unwrap());

// Gets a value for config if supplied by user, or defaults to "default.conf"
let config = matches.value_of("CONFIG").unwrap_or("default.conf");
println!("Value for config: {}", config);

(Copied from the official documentation)

Solution 5 - Command Line

As of version 0.8/0.9, the correct path to the function args() would be ::std::os::args, i.e.:

fn main() {
  let args: ~[~str] = ::std::os::args();
  println(args[0]);
}

It seems that Rust is still pretty volatile right now with even standard I/O, so this may become out of date fairly quickly.

Solution 6 - Command Line

Rust changed again. os::args() is deprecated in favor of std::args(). But std::args() is not an array, it returns an iterator. You can iterate over the command line arguments, but cannot access them with subscripts.

http://doc.rust-lang.org/std/env/fn.args.html

If you want the command line arguments as a vector of strings, this will work now:

use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();

Rust - learn to embrace the pain of change.

Solution 7 - Command Line

Also check out structopt:

extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
    /// A flag, true if used in the command line.
    #[structopt(short = "d", long = "debug", help = "Activate debug mode")]
    debug: bool,

    /// An argument of type float, with a default value.
    #[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
    speed: f64,

    /// Needed parameter, the first on the command line.
    #[structopt(help = "Input file")]
    input: String,

    /// An optional parameter, will be `None` if not present on the
    /// command line.
    #[structopt(help = "Output file, stdout if not present")]
    output: Option<String>,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}

https://github.com/TeXitoi/structopt

Solution 8 - Command Line

What barjak said works for strings, but if you need the argument as a number (in this case a uint) you need to convert like this:

fn main() {
    let arg : ~[~str] = os::args();
    match uint::from_str(arg[1]){
         Some(x)=>io::println(fmt!("%u",someFunction(x))),
         None=>io::println("I need a real number")
    }
}

Solution 9 - Command Line

As of newer Rust versions (Rust > 0.10/11) the array syntax won't work. You will have to use the get method.

The array syntax works (again) in the nightly. So you can choose between the getter or array index.

use std::os;

fn main() {
  let args = os::args();
  println!("{}", args.get(1));
}

// Compile
rustc args.rs && ./args hello-world // returns hello-world

Solution 10 - Command Line

Rust has evolved since Calvin's answer from May 2013. Now one would parse command line arguments with as_slice():

use std::os;

fn seen_arg(x: uint)
{       
    println!("you passed me {}", x);
}
fn main() {
    let args = os::args();
    let args = args.as_slice();
    let nitems = {
            if args.len() == 2 {
                    from_str::<uint>(args[1].as_slice()).unwrap()
            } else {
                    10000
            }
    };

    seen_arg(nitems);
}

Solution 11 - Command Line

The Rust book "No stdlib" chapter covers how to access the command lines parameters (another way).

// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    0
}

Now, the example does also have #![no_std] which I think means that normally, the std library would have the true entry point for your binary and call a global function called main(). Another options is to 'disable the main shim' with #![no_main]. Which if I'm not mistaken is saying to the compiler that you are taking full control over how your program is started.

#![no_std]
#![no_main]

#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: isize, argv: *const *const u8) -> isize {
    0
}

I do not think this is a 'good' way of doing things if all you want to do is read command line arguments. The std::os module mentioned in other answers seems to be a much better way of doing things. I post this answer for the sake of completion.

Solution 12 - Command Line

If you want to iterate over command-line arguments:

use std::env::{args,Args};

fn main() {
    let mut args:Args=args();
    // args.nth(0) cannot borrow as mutable. that is why  let mut args
    // nth return an element of iterator
    let first=args.nth(1).unwrap();
    // iterator has next method. we want to get the first element of next iterator. NOT args.nth(2)
    // chars returns an iterator
    let operator=args.nth(0).unwrap().chars().next().unwrap();
    let second=args.nth(0).unwrap();
}

If you want to access the n'th argument directly:

fn get_nth_arg(n:usize)->String{
    std::env::args().nth(n).unwrap()
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshutefanView Question on Stackoverflow
Solution 1 - Command LinebarjakView Answer on Stackoverflow
Solution 2 - Command LineBurntSushi5View Answer on Stackoverflow
Solution 3 - Command LineTobuView Answer on Stackoverflow
Solution 4 - Command LinemreView Answer on Stackoverflow
Solution 5 - Command LineNickView Answer on Stackoverflow
Solution 6 - Command LineJohn NagleView Answer on Stackoverflow
Solution 7 - Command LinemreView Answer on Stackoverflow
Solution 8 - Command LineCalvinView Answer on Stackoverflow
Solution 9 - Command LinepatView Answer on Stackoverflow
Solution 10 - Command LineRob LathamView Answer on Stackoverflow
Solution 11 - Command LinethecoshmanView Answer on Stackoverflow
Solution 12 - Command LineYilmazView Answer on Stackoverflow