Rust命令行工具生成库make-cmd的使用,快速构建高效可扩展的CLI应用程序
Rust命令行工具生成库make-cmd的使用,快速构建高效可扩展的CLI应用程序
安装
在项目目录中运行以下Cargo命令:
cargo add make-cmd
或者在Cargo.toml中添加以下行:
make-cmd = "0.1.0"
使用示例
以下是一个完整的示例demo,展示如何使用make-cmd库构建CLI应用程序:
use make_cmd::cmd;
// 定义你的CLI命令结构
#[derive(Debug, cmd::Command)]
struct MyCli {
/// 输入文件路径
#[cmd(arg)]
input: String,
/// 输出文件路径 (可选)
#[cmd(arg, optional)]
output: Option<String>,
/// 详细输出
#[cmd(flag, short = 'v')]
verbose: bool,
/// 线程数 (默认为1)
#[cmd(option, short = 't', default = "1")]
threads: usize,
}
fn main() {
// 解析命令行参数
let cli = MyCli::parse();
println!("解析得到的CLI参数: {:?}", cli);
// 在这里添加你的应用程序逻辑
if cli.verbose {
println!("详细模式已启用");
}
println!("使用 {} 个线程处理文件", cli.threads);
}
功能说明
-
参数解析:
#[cmd(arg)]
- 必需的位置参数#[cmd(arg, optional)]
- 可选的位置参数#[cmd(flag)]
- 布尔标志#[cmd(option)]
- 带值的选项
-
自动生成帮助信息:
- 结构体字段的文档注释会自动成为CLI帮助信息的一部分
- 支持
-h
或--help
显示帮助
-
自定义选项:
- 使用
short
属性指定短选项名 - 使用
default
属性指定默认值
- 使用
构建和运行
构建并运行你的CLI应用程序:
cargo build
./target/debug/your_binary --help # 查看帮助信息
./target/debug/your_binary input.txt -v -t 4 # 运行示例
这个示例展示了如何使用make-cmd快速构建一个功能完整的CLI应用程序,包括参数解析、帮助生成和默认值处理等功能。
完整示例代码
下面是一个更完整的示例,展示了make-cmd库的高级用法:
use make_cmd::cmd;
use std::path::PathBuf;
/// 一个更复杂的CLI应用程序示例
#[derive(Debug, cmd::Command)]
struct AdvancedCli {
/// 操作模式 (create|delete|list)
#[cmd(arg)]
mode: String,
/// 目标文件路径
#[cmd(arg)]
file: PathBuf,
/// 递归操作
#[cmd(flag, short = 'r')]
recursive: bool,
/// 操作确认
#[cmd(flag, short = 'y')]
confirm: bool,
/// 日志级别 (debug|info|warn|error)
#[cmd(option, short = 'l', default = "info")]
log_level: String,
/// 配置文件路径
#[cmd(option, short = 'c')]
config: Option<PathBuf>,
/// 额外参数 (可多个)
#[cmd(arg, optional, multiple)]
extra_args: Vec<String>,
}
fn main() {
let cli = AdvancedCli::parse();
match cli.mode.as_str() {
"create" => {
println!("创建文件: {:?}", cli.file);
if cli.recursive {
println!("递归模式已启用");
}
},
"delete" => {
if !cli.confirm {
eprintln!("请使用 -y 确认删除操作");
return;
}
println!("删除文件: {:?}", cli.file);
},
"list" => {
println!("列出文件: {:?}", cli.file);
},
_ => {
eprintln!("未知模式: {}", cli.mode);
return;
}
}
println!("日志级别: {}", cli.log_level);
if let Some(config_path) = cli.config {
println!("使用配置文件: {:?}", config_path);
}
if !cli.extra_args.is_empty() {
println!("额外参数: {:?}", cli.extra_args);
}
}
这个完整示例展示了:
- 枚举式参数(mode)
- 路径参数(PathBuf)
- 多个布尔标志
- 默认值设置
- 可选配置参数
- 多个额外参数的处理
- 基本的错误处理逻辑
可以通过以下命令测试:
# 查看帮助
cargo run -- --help
# 创建文件示例
cargo run -- create test.txt -r -l debug -c config.toml arg1 arg2
# 删除文件示例
cargo run -- delete test.txt -y
1 回复
Rust命令行工具生成库make-cmd使用指南
简介
make-cmd
是一个Rust库,用于快速构建高效且可扩展的命令行接口(CLI)应用程序。它简化了命令行参数解析、子命令管理和帮助文档生成的过程,让开发者能专注于业务逻辑的实现。
主要特性
- 简洁的API设计
- 自动生成帮助文档
- 支持嵌套子命令
- 类型安全的参数解析
- 可扩展的命令结构
安装
在Cargo.toml
中添加依赖:
[dependencies]
make-cmd = "0.1"
基本使用方法
1. 创建简单命令
use make_cmd::Command;
fn main() {
let cmd = Command::new("greet")
.about("A simple greeting application")
.version("1.0.0")
.arg("name", "The person to greet")
.action(|args| {
let name = args.get_one::<String>("name").unwrap();
println!("Hello, {}!", name);
Ok(())
});
cmd.run();
}
运行示例:
$ greet Rust
Hello, Rust!
2. 创建带子命令的应用
use make_cmd::{Command, SubCommand};
fn main() {
let cmd = Command::new("file-manager")
.about("A simple file manager")
.version("1.0.0")
.subcommand(
SubCommand::new("create")
.about("Create a new file")
.arg("filename", "Name of the file to create")
.action(|args| {
let filename = args.get_one::<String>("filename").unwrap();
std::fs::File::create(filename)?;
println!("Created file: {}", filename);
Ok(())
})
)
.subcommand(
SubCommand::new("delete")
.about("Delete a file")
.arg("filename", "Name of the file to delete")
.action(|args| {
let filename = args.get_one::<String>("filename").unwrap();
std::fs::remove_file(filename)?;
println!("Deleted file: {}", filename);
Ok(())
})
);
cmd.run();
}
运行示例:
$ file-manager create test.txt
Created file: test.txt
$ file-manager delete test.txt
Deleted file: test.txt
3. 添加可选参数和标志
use make_cmd::Command;
fn main() {
let cmd = Command::new("calculator")
.about("A simple calculator")
.version("1.0.0")
.arg("x", "First number")
.arg("y", "Second number")
.flag("add", "Add the numbers")
.flag("multiply", "Multiply the numbers")
.action(|args| {
let x: f64 = args.get_one("x").unwrap();
let y: f64 = args.get_one("y").unwrap();
if args.is_present("add") {
println!("Result: {}", x + y);
} else if args.is_present("multiply") {
println!("Result: {}", x * y);
} else {
println!("Please specify an operation (--add or --multiply)");
}
Ok(())
});
cmd.run();
}
运行示例:
$ calculator 5 3 --add
Result: 8
$ calculator 5 3 --multiply
Result: 15
高级用法
1. 自定义参数解析器
use make_cmd::{Command, Arg};
use std::str::FromStr;
struct Point {
x: i32,
y: i32,
}
impl FromStr for Point {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(',').collect();
if parts.len() != 2 {
return Err("Point must be in format 'x,y'".to_string());
}
Ok(Point {
x: parts[0].parse().map_err(|_| "Invalid x coordinate".to_string())?,
y: parts[1].parse().map_err(|_| "Invalid y coordinate".to_string())?,
})
}
}
fn main() {
let cmd = Command::new("point-ops")
.about("Point operations")
.arg(Arg::new("point")
.help("Point in format 'x,y'")
.required(true)
.parser::<Point>())
.action(|args| {
let point = args.get_one::<Point>("point").unwrap();
println!("Point coordinates: ({}, {})", point.x, point.y);
Ok(())
});
cmd.run();
}
运行示例:
$ point-ops 10,20
Point coordinates: (10, 20)
2. 异步命令处理
use make_cmd::Command;
use tokio::fs;
#[tokio::main]
async fn main() {
let cmd = Command::new("async-file")
.about("Async file operations")
.arg("filename", "File to read")
.async_action(|args| async move {
let filename = args.get_one::<String>("filename").unwrap();
let contents = fs::read_to_string(filename).await?;
println!("File contents:\n{}", contents);
Ok(())
});
cmd.run_async().await;
}
最佳实践
- 模块化设计:将不同子命令的实现放在不同的模块中
- 错误处理:使用
anyhow
或thiserror
库进行友好的错误处理 - 测试:为每个命令和子命令编写单元测试
- 文档:为每个命令和参数添加详细的帮助文本
- 性能:对于CPU密集型操作,考虑使用
rayon
进行并行处理
完整示例
下面是一个完整的文件管理工具示例,结合了基本和高级用法:
use make_cmd::{Command, SubCommand, Arg};
use std::path::PathBuf;
use anyhow::Result;
// 定义自定义文件大小类型
#[derive(Debug)]
struct FileSize(u64);
impl std::str::FromStr for FileSize {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let size = s.parse().map_err(|_| "Invalid file size".to_string())?;
Ok(FileSize(size))
}
}
fn main() -> Result<()> {
let cmd = Command::new("file-tool")
.about("Advanced file management tool")
.version("1.0.0")
.subcommand(
SubCommand::new("info")
.about("Get file information")
.arg(Arg::new("path")
.help("File path")
.required(true))
.arg(Arg::new("human-readable")
.help("Show size in human readable format")
.short('h')
.long("human-readable")
.takes_value(false))
.action(|args| {
let path = args.get_one::<String>("path").unwrap();
let metadata = std::fs::metadata(path)?;
if args.is_present("human-readable") {
println!("Size: {} KB", metadata.len() / 1024);
} else {
println!("Size: {} bytes", metadata.len());
}
Ok(())
})
)
.subcommand(
SubCommand::new("search")
.about("Search files")
.arg(Arg::new("directory")
.help("Directory to search")
.required(true))
.arg(Arg::new("extension")
.help("File extension filter")
.short('e')
.long("extension"))
.arg(Arg::new("min-size")
.help("Minimum file size in bytes")
.long("min-size")
.parser::<FileSize>())
.async_action(|args| async move {
let dir = args.get_one::<String>("directory").unwrap();
let extension = args.get_one::<String>("extension");
let min_size = args.get_one::<FileSize>("min-size");
// 异步文件搜索逻辑
search_files(dir, extension, min_size).await?;
Ok(())
})
);
cmd.run()?;
Ok(())
}
async fn search_files(dir: &str, extension: Option<&String>, min_size: Option<&FileSize>) -> Result<()> {
// 实现异步文件搜索逻辑
println!("Searching in: {}", dir);
println!("Filters - Extension: {:?}, Min Size: {:?}", extension, min_size);
Ok(())
}
总结
make-cmd
为Rust开发者提供了一个简单而强大的工具来构建CLI应用程序。通过其直观的API和丰富的功能,你可以快速创建出专业级的命令行工具,而无需花费大量时间处理参数解析和帮助文档生成等底层细节。