Как получить доступ к параметрам командной строки?


The учебник Руст не объясняет, как принять параметры из командной строки. fn main() отображается только с пустым списком параметров во всех примерах.

Что такое правильный способ доступа к параметрам командной строки main?

11 122

11 ответов:

вы можете получить доступ к аргументам командной строки с помощью тега std::env::args или std::env::args_os функции. Обе функции возвращают итератор над аргументами. Первый перебирает Strings (с которыми легко работать), но паникует, если один из аргументов не является допустимым unicode. Последний перебирает OsStringS и никогда не паникует.

обратите внимание, что первый элемент итератора-это имя самой программы (это соглашение во всех основных ОС), таким образом, первый аргумент на самом деле является вторым итерированным элементом.

простой способ справиться с результатом args преобразовать его в Vec:

use std::env;

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

можно использовать стандартный набор инструментов итератора для работы с этими доводами. Например, чтобы получить только первый аргумент:

use std::env;

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

вы можете найти библиотеки на crates.io для разбора командной строки аргументы:

  • docopt: вы просто пишете сообщение справки, и код разбора генерируется для вас.
  • хлоп: вы описываете параметры, которые вы хотите проанализировать с помощью fluent API. Быстрее, чем docopt и дает вам больше контроля.
  • getopts: порт популярной библиотеки C. Более низкий уровень и даже больше контроля.
  • structopt: построенный поверх хлопка, это еще больше эргономичный в использовании.

Docopt также доступна для Rust, которая генерирует парсер для вас из строки использования. В качестве бонуса в Rust можно использовать макрос для автоматического создания структуры и декодирования на основе типа:

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

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

и вы можете получить args с:

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

README и документация есть много полных рабочих примеров.

отказ от ответственности: я один из авторов этой библиотеки.

Руст использования getopt-стиле командной строки разбора аргумент в модуль getopts.

для меня getopts всегда чувствовал себя слишком низкоуровневым и docopt.rs было слишком много магии. Я хочу что-то явное и простое, что по-прежнему предоставляет все функции, если они мне нужны.

вот тут хлоп-РС приходит в сподручное.
Это немного похоже на argparse из Python. Вот пример того, как это выглядит:

let matches = App::new("myapp")
                      .version("1.0")
                      .author("Kevin K. <kbknapp@gmail.com>")
                      .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();

вы можете получить доступ к своим параметрам следующим образом:

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);

(скопированный с официальный документация)

начиная с версии 0.8 / 0.9, правильный путь к функции args () будет ::std::os::args, например:

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

Кажется, что ржавчина все еще довольно изменчива прямо сейчас даже со стандартным IO, поэтому это может стать устаревшим довольно быстро.

ржавчина снова изменилась. os::args() является устаревшим в пользу std::args(). Но std::args() не является массивом, он возвращает итератор. Вы можете перебирать аргументы командной строки, но не можете получить к ним доступ с помощью индексов.

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

если вы хотите аргументы командной строки как вектор строк, это будет работать так:

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

ржавчина-научитесь принимать боль изменение.

то, что сказал @barjak, работает для строк, но если вам нужен аргумент в виде числа (в данном случае uint), вам нужно преобразовать следующим образом:

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")
    }
}

в новых версиях Rust (Rust > 0.10/11) синтаксис массива не будет работать. Вам придется использовать метод get.

[Edit] синтаксис массива работает (снова) в ночное время. Таким образом, вы можете выбрать между геттером или индексом массива.

use std::os;

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

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

ржавчина эволюционировала с момента ответа Кальвина с мая 2013 года. Теперь можно было бы разобрать аргументы командной строки с помощью 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);
}

The книга ржавчины" нет stdlib " глава описано, как получить доступ к параметрам командной строки (другой способ).

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

теперь в Примере также есть #![no_std] что, я думаю, означает, что обычно библиотека std будет иметь истинную точку входа для вашего двоичного файла и вызывать глобальную функцию с именем main(). Другой вариант - " отключить main ШИМ с #![no_main]. Что, если я не ошибаюсь, говорит компилятору, что вы берете полный контроль над тем, как ваша программа запущена.

#![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
}

я не думаю, что это хороший способ делать вещи, если все вы хотите сделать, это прочитать аргументы командной строки. Элемент std::os модуль, упомянутый в других ответах, кажется, гораздо лучший способ делать вещи. Я публикую этот ответ ради завершения.

также проверьте 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