명령 행 매개 변수에 액세스하는 방법?


153

녹 튜토리얼은 명령 줄에서 매개 변수를 사용하는 방법에 대해 설명하지 않습니다. fn main()모든 예제에서 빈 매개 변수 목록으로 만 표시됩니다.

에서 명령 줄 매개 변수에 액세스하는 올바른 방법은 무엇입니까 main?

답변:


168

std::env::args또는 std::env::args_os함수 를 사용하여 명령 줄 인수에 액세스 할 수 있습니다 . 두 함수 모두 인수에 대해 반복자를 반환합니다. 전자는 Strings (작업하기 쉬운)를 반복 하지만 인수 중 하나가 유효한 유니 코드가 아닌 경우 패닉 상태입니다. 후자는 반복된다OsString s를 하고 결코 당황하지 않습니다.

반복자의 첫 번째 요소는 프로그램 자체의 이름 (모든 주요 OS의 규칙)이므로 첫 번째 인수는 실제로 두 번째 반복 된 요소입니다.

결과를 처리하는 쉬운 방법은 다음과 같이 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 : 도움말 메시지를 작성하면 구문 분석 코드가 생성됩니다.
  • 박수 : 유창한 API를 사용하여 구문 분석하려는 옵션을 설명합니다. docopt보다 빠르며 더 많은 제어 기능을 제공합니다.
  • getopts : 널리 사용되는 C 라이브러리의 포트 더 낮은 수준의 제어 기능
  • structopt : 박수 위에 제작되어 사용하기가 더 인체 공학적입니다.

2
또한 0.8 녹으로 그냥 사용해야합니다println(args[0])
Leo Correa

6
위의 의견 (@LeoCorrea / @ S4M)은 이전 버전의 답변을 언급했습니다. 답변의 현재 버전에는 최신 정보가 포함되어 있습니다.
Nickolay

22

Rust에서도 Docopt 를 사용할 수 있으며, 이는 사용 문자열에서 파서를 생성합니다. Rust의 보너스로 매크로를 사용하여 구조체를 자동으로 생성하고 형식 기반 디코딩을 수행 할 수 있습니다.

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

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

그리고 당신은 다음과 같이 인수를 얻을 수 있습니다 :

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

README와 문서 에는 전체 실무 예제가 많이 있습니다.

면책 조항 : 나는이 도서관의 저자 중 하나입니다.



10

저에게는 getopts가 항상 너무 낮게 느껴졌고 docopt.rs는 너무 많은 마법이었습니다. 필요한 경우 여전히 모든 기능을 제공하는 명시적이고 간단한 것을 원합니다.

이것은 clap-rs 가 유용한 곳입니다.
파이썬의 argparse와 비슷합니다. 다음은 그 모습에 대한 예입니다.

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

( 공식 문서 에서 복사 )


1
clap-rs를 사용하면 yaml 파일로 인터페이스를 정의 할 수 있습니다. 또한 정말 멋진 사용법 구문을 생성합니다.
Chuck Wooters

이를 통해 CLI 앱을 빠르게 설정할 수있었습니다. 감사합니다!
dimitarvp

4

버전 0.8 / 0.9부터 args () 함수의 올바른 경로는 다음 ::std::os::args과 같습니다.

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

Rust는 여전히 표준 IO조차도 여전히 휘발성이기 때문에 상당히 빨리 구식이 될 수 있습니다.


업데이트 해 주셔서 감사합니다! 1.0이 출시 된 후 승인 된 답변을 재고해야한다고 생각합니다.
shutefan

3

녹이 다시 바뀌었다. 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();

녹-변화의 고통을 받아들이는 법을 배웁니다.


8
당신은 이제 할 필요가 env::args().collect()있습니다.
tshepang

2

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

2

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


1

최신 Rust 버전 (Rust> 0.10 / 11)부터는 배열 구문이 작동하지 않습니다. get 메소드를 사용해야합니다.

[편집] 배열 구문은 밤마다 작동합니다. 따라서 getter 또는 배열 인덱스 중에서 선택할 수 있습니다.

use std::os;

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

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

이것은 쓸모없는 진술입니다. 최신 Rust nightlies는의 인덱싱 구문을 지원합니다 Vec. 한 달 정도있을 것 같아요. 이 예제를 참조하십시오 .
Vladimir Matveev

1

Rust는 2013 년 5 월부터 Calvin의 답변 이후 발전했습니다. 이제 명령 행 인수를 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);
}

단지 기록을 위해 : as_slice()더 이상 존재하지 않으며 &args대신 사용해야합니다.
Slava Semushin

1

녹 책은 "아니오 다음 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다른 답변에서 언급 한 모듈은 일을 더 나은 방법이 될 것으로 보인다. 이 답변을 완성을 위해 게시합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.