Rust命令行参数解析:使用clap

Rust命令行参数

Rust程序的命令行参数,可以通过std::env::args_os函数取得。

std::env::args_os函数的原型为:

pub fn args_os() -> ArgsOs

其中,ArgsOs是一个迭代器,每一个迭代值都是一个OSString。

我们知道,OSString可能包含非法的UTF-8字符。如果要只接受合法的UTF-8字符,在出现非法UTF-8字符的情况下崩溃程序,可以使用std::env::args函数。

std::env::args函数的原型与args_os类似,只是返回值是Args,即String的迭代器。

pub fn args() -> Args

解析命令行参数

我们可以取得std::env::args_os或者std::env::args函数的返回值之后,手动解析。

如:

use std::env;

for argument in env::args_os() {
    println!("{argument:?}");
}

就把每一个命令行参数打印了出来。

旧式clap解析

手动解析命令行参数比较麻烦,我们可以使用成熟的crate,比如clap。

使用cargo构建的Rust程序,可以通过

cargo add clap

来添加clap依赖。

之后,就可以在Rust程序中,使用clap来解析命令行参数了。

比较早期的clap,比如2.0.0版本,是通过clap::App以及clap::Arg来解析。

如《Rust实战》中这段样例代码:

use regex::Regex; 
use clap::{App,Arg}; ⇽--- 导入clap::App和clap::Arg对象到当前的局部作用域。 
 
fn main() { 
    let args = App::new("grep-lite") ⇽--- 逐步构建命令行参数解析器。每个参数对应一个Arg。在本例中,我们只需要一个参数。 
    .version("0.1") 
    .about("searches for patterns") 
    .arg(Arg::with_name("pattern") 
    .help("The pattern to search for") 
    .takes_value(true) 
    .required(true)) 
    .get_matches(); 

    let pattern = args.value_of("pattern").unwrap(); ⇽--- 提取pattern参数。 
    let re = Regex::new(pattern).unwrap(); 
    ……
}

通过以上代码以及注释,可以大概了解到,使用clap 2 解析命令行参数的过程就是:

  1. 通过clap::App结构的new方法,生成一个App。
  2. 添加Arg,设置help、about等到App。
  3. 调用App的get_matches方法。
  4. 通过get_matches方法返回的ArgMatches结构的value_of方法,取得解析出来的参数值。

新版本clap解析,以4.5.20为例

如果使用的是比较新的clap,如4.5.20,则会发现已没有clap::App这个结构,取而代之的是clap::Command,而且clap::Arg的构造方法也有了变化。

4.5.20的clap中包含Arg、ArgGroup、ArgMatches、Command以及Id等结构,另外有arg、command、value_parser等宏,还有Args、CommandFactory、FromArgMatches、Parser、SubCommand、ValueEnum等特性。

如以下代码,可以生成一个Command之后调用get_matches取得解析出来的ArgMatches结构:

let m = Command::new("My Program")
    .author("Me, me@mail.com")
    .version("1.0.2")
    .about("Explains in brief what the program does")
    .arg(
        Arg::new("in_file")
    )
    .after_help("Longer explanation to appear after the options when \
                 displaying the help information from --help or -h")
    .get_matches();

值得一提的是,Command有一个subcommand函数,可以实现子命令解析的功能。

如:

fn main {
// 生成一个check的子命令
let _check_command = Command::new("check")
.arg(Arg::new("init")
    .long("init")
    .action(ArgAction::SetTrue)
    .help("init the database"),
    ))

// 生成一个hello的命令
let _command = Command::new("hello")
.version("0.0.1")
.arg(Arg::new("config-file") // 增加一个config-file的参数
    .short('c')
    .long("config-file")
    .required(false)
    .default_value("/etc/hello.cfg"))
.subcommand(_check_command); // 增加一个check的子命令

let _matches = _command.get_matches();
}

编译上述代码,得到hello。

使用./hello -V命令,则会得到:

./hello -V  
hello 0.0.1

使用./hello -h或者./hello --help命令,则会得到:

./hello --help  
Usage: hello [OPTIONS] [COMMAND]  
  
Commands:  
 check     
 help   Print this message or the help of the given subcommand(s)  
  
Options:  
 -c, --config-file <config-file>  [default: /etc/hello.cfg]  
 -h, --help                 Print help  
 -V, --version              Print version

我们看到,在Commands里面,有一个check命令以及help命令。

我们使用./hello check --help命令,则会看到:

./hello check --help  
Usage: hello check [OPTIONS]  
  
Options:  
     --init               init the check database    
 -h, --help               Print help

即,我们有了一个子命令check,还接受子命令参数–init以及-h、–help。

取得子命令参数

我们可以通过clap::ArgMatches的subcommand函数,来取得子命令的参数。

ArgMatches的subcommand的原型为:

pub fn subcommand(&self) -> Option<(&str, &ArgMatches)>

所以,我们可以通过subcommand的结果,取得子命令的值,以及子命令的参数。

如:

 let app_m = Command::new("git")
     .subcommand(Command::new("clone"))
     .subcommand(Command::new("push"))
     .subcommand(Command::new("commit"))
     .get_matches();

match app_m.subcommand() {
    Some(("clone",  sub_m)) => {}, // clone was used
    Some(("push",   sub_m)) => {}, // push was used
    Some(("commit", sub_m)) => {}, // commit was used
    _                       => {}, // Either no subcommand or one not tested for...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值