用 clap 解析用户输入的字符串以进行命令行编程

问题描述 投票:0回答:3

我想创建一个命令行,利用 clap 来解析输入。我能想到的最好的办法是一个循环,要求用户输入,用正则表达式将其分解并构建一个 Vec,它以某种方式传递给

loop {
    // Print command prompt and get command
    print!("> "); io::stdout().flush().expect("Couldn't flush stdout");

    let mut input = String::new(); // Take user input (to be parsed as clap args)
    io::stdin().read_line(&mut input).expect("Error reading input.");
    let args = WORD.captures_iter(&input)
           .map(|cap| cap.get(1).or(cap.get(2)).unwrap().as_str())
           .collect::<Vec<&str>>();

    let matches = App::new("MyApp")
        // ... Process Clap args/subcommands
    .get_matches(args); //match arguments from CLI args variable
}

基本上,我想知道是否有办法让 Clap 使用预先给定的参数列表?

rust command-line-interface clap
3个回答
6
投票

正如@mcarton 所说,命令行程序将其参数作为数组而不是字符串传递。 shell 拆分了原始命令行(考虑到引号、变量扩展等)。

如果您的要求很简单,您可以简单地将字符串拆分为空格并将其传递给 Clap。或者,如果你想尊重引用的字符串,你可以使用 shellwords 来解析它:

let words = shellwords::split(input)?;
let matches = App::new("MyApp")
    // ... command line argument options
    .get_matches_from(words);

1
投票

这就是我最终让整个事情发挥作用的方式:

首先,我将我的整个主要功能放在

loop
中,以便它能够获取命令,并且留在 CLI 中。

接下来,我通过

stdin
获得输入并拆分参数

// Print command prompt and get command
print!("> ");
io::stdout().flush().expect("Couldn't flush stdout");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Error reading input.");
let args = WORD.captures_iter(&input)
           .map(|cap| cap.get(1).or(cap.get(2)).unwrap().as_str())
           .collect::<Vec<&str>>();

然后我使用 Clap 来解析,有点像@harmic 建议的

let matches = App::new("MyApp")
    // ... command line argument options
    .get_matches_from(words);

并使用

subcommands
而不是
arguments
.

例如

.subcommand(SubCommand::with_name("list")
    .help("Print namespaces currently tracked in the database."))

整个文件是here好奇的。


0
投票

而不是使用

parse
,您可以使用
parse_from
,它允许您指定迭代器。

use clap::Parser;

#[derive(Debug, Parser, Default)]
#[command(about, version, no_binary_name(true))]
struct Cli {
    #[arg(long, short, default_value_t = String::from("Default endpoint"))]
    /// RPC endpoint of the node that this wallet will connect to
    endpoint: String,

    #[arg(long, short)]
    refresh_rate: Option<u32>,
}

fn main() {
    let input = vec!["--endpoint", "localhost:8000", "--refresh-rate", "15"];

    let c = Cli::parse_from(input);

    println!("{:?}", c);
}
© www.soinside.com 2019 - 2024. All rights reserved.