command用法

设置command

输出version

use clap::Parser;

#[derive(Parser, Debug)]
// version没有定义,导入Cargo.toml的package.version
#[command(name="app", version)]
struct Cli {
    #[arg(short, long)]
    debug: bool
}


fn main() {
    let cli = Cli::parse();
    println!("Hello, {:?}!", cli);
}
target/debug/test_clap --version
app 0.1.0

设置name

  • name = clap 内部的命令名字
    • Cli::command().get_name()获取name值
  • bin_name = 用户在终端里输入的命令名字
    • 体现在Usage: XX_NAME [OPTIONS]
[package]
name = "test_clap"
version = "0.1.0"
edition = "2024"

[dependencies]
clap = { version = "4.6.6", features = ["derive", "env", "color"] }

# 设置二进制文件输出
[[bin]]
name = "myapp"
path = "src/main.rs"
use clap::{Parser, CommandFactory};

#[derive(Parser, Debug)]
// 设置name和bin_name
#[command(name="myapp", bin_name="myapp", version)]
struct Cli {
    #[arg(short, long)]
    debug: bool
}


fn main() {
    let cli = Cli::parse();
    println!("Hello, {:?}!", cli);
    // 可以获取name名字, 需要导入CommandFactory
    println!("{}", Cli::command().get_name());
}
cargo run -- -d
     Running `target/debug/myapp -d` # 输出的二进制文件名被toml改了
Hello, Cli { debug: true }!
myapp1	# 获取了name值

name的优先级

  • 系统传入: argv[0] = "test_clap"
  • Clap Command
    • name = "abc" ← 逻辑名称程序中使用
    • bin_name = "myapp" ← 展示名称Usage
    • argv[0] = "clap_test" ← 默认值
  • Usage显示优先级:bin_name > argv[0] > name

说明about/long_about

long_about=None-h--help都使用about的内容

use clap::Parser;

#[derive(Parser, Debug)]

#[command(
    name = "myapp",
    version = "1.0.0",
    about = "关于工具简短说明",
    long_about="设置一个好用的long_about文本内容")
]
struct Cli {
    #[arg(short, long)]
    debug: bool
}


fn main() {
    let cli = Cli::parse();
    println!("Hello, {:?}!", cli);
}
# -h显示about
target/debug/myapp -h
关于工具简短说明

Usage: myapp [OPTIONS]
...

# --help显示long_about
target/debug/myapp --help
设置一个好用的long_about文本内容

Usage: myapp [OPTIONS]
...

额外说明before_help/after_help

use clap::Parser;

#[derive(Parser, Debug)]

#[command(
    name = "myapp",
    bin_name = "myapp",
    version = "1.0.0",
    about = "关于工具简短说明",
    long_about="设置一个好用的long_about文本内容",
    before_help = "使用前请阅读文档: https://example.com/docs",
    after_help = "示例:\n  myapp add foo --desc '测试'\n  myapp remove 123 --force",
)]
struct Cli {
    #[arg(short, long)]
    debug: bool
}


fn main() {
    let cli = Cli::parse();
    println!("Hello, {:?}!", cli);
}
target/debug/myapp -h
使用前请阅读文档: https://example.com/docs # before_help说明内容

关于工具简短说明 # about内容

Usage: myapp [OPTIONS]

Options:
  -d, --debug    
  -h, --help     Print help (see more with '--help')
  -V, --version  Print version

示例: # after_help内容
  myapp add foo --desc '测试'
  myapp remove 123 --force

自定义显示help_template

变量 说明 示例输出
{name} 程序名 myapp
{version} 版本号 1.0.0
{author} 作者信息 张三
{about} 简短描述(不含换行) 我的工具
{about-with-newline} 简短描述(带换行) 我的工具\n
{long-about} 详细描述 这是一个详细的说明...
{usage-heading} "Usage:" 标题 Usage:
{usage} 用法字符串 myapp [OPTIONS] <NAME>
{all-args} 所有参数列表 -h, --help...
{options} 选项列表 -n, --name...
{positionals} 位置参数列表 <NAME>
{subcommands} 子命令列表 add, remove...
{before-help} before_help 内容 (自定义)
{after-help} after_help 内容 (自定义)

简洁版

help_template = "{name} {version}\n{about}\n\n{usage-heading} {usage}\n\n{all-args}"

完整版

help_template = "\
{name} {version}
作者: {author}
{about-with-newline}
{usage-heading} {usage}

选项:
{options}

子命令:
{subcommands}

{after-help}"

设置文本宽度term_width

  • 限制帮助文本最大宽度,自动换行
#[command(term_width = 80)]

command开关选项

disable_help_flag

  • 关闭-h--help开关
#[command(disable_help_flag = true)]

disable_version_flag

  • 关闭-v--version开关
#[command(disable_version_flag = true)]

帮助换行显示

  • 帮助换行显示,默认是紧凑显示
#[command(next_line_help = true)]

关闭枚举默认值

#[command(hide_possible_values = true)]
// 需要导入ValueEnum
use clap::{Parser, ValueEnum};

#[derive(Debug, Clone, ValueEnum)]
enum LogLevel {
    Debug,
    Info,
    Warn,
    Error,
}

#[derive(Parser, Debug)]
#[command(hide_possible_values = true)]
struct MyCli {
    // 需要定义value_enum
    // 设置default_value_t默认值
    #[arg(short, long, value_enum, default_value_t = LogLevel::Info)]
    log: LogLevel
}

fn main() {
    let cli = MyCli::parse();
    println!("cli.name: {:?}", cli.log);
}
Usage: myapp [OPTIONS]

Options:
  -l, --log <LOG>  [default: info]
  -h, --help       Print help

允许负数

  • commandallow_negative_numbers是全局范围,argallow_hyphen_values是单个范围
#[command(allow_negative_numbers = true)]  

重复参数覆盖

  • args_override_self允许后面的值覆盖前面的值,而不是报错
  • 默认情况下,同一个参数传多次会报错
#[command(args_override_self = true)]
use clap::Parser;
#[derive(Parser, Debug)]
#[command(args_override_self = true)]
struct MyCli {
    #[arg(short, long)]
    name: String
}

fn main() {
    let cli = MyCli::parse();
    println!("cli.name: {:?}", cli.name);
}
target/debug/myapp -n aa -n bb
cli.name: "bb"

子命令

创建子命令

⚠️#[command(name = "myapp")]里面只能有一个#[command(subcommand)]

``#[command(subcommand)]里面可以多个#[command(subcommand)]`(子命令嵌套)

use clap::{Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "myapp")]
struct Cli {
  	// command这个key可以随便起名
    #[command(subcommand)] // 标记子命令入口
    command: MyCommands,
}

// 定义子命令
#[derive(Subcommand, Debug)]
enum MyCommands {
  	// 子命令选项
    Add,
    Remove,
    List,
}

fn main() {
    let cli = Cli::parse();
    println!("{:?}", cli);
}
Usage: myapp <COMMAND>

Commands:
  add     
  remove  
  list    
  help    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

子命令参数

  • 如果字段没有 #[arg(...)] 属性 → 默认解析为位置参数(Positional Argument),即不带 ---,按顺序输入。
  • 如果字段添加了 #[arg(short, long)] → 才会解析为选项(Option),即带 --xxx-x 的标志参数。

参数是否必填

类型 解释 参数数量 是否必填
String 单一确定的值 恰好 1 个 必填
Option<String> 可能有,可能没有 0 个 或 1 个 可选
Vec<String> 零个、一个或多个值的集合 0 个 或 N 个 可选

位置参数

use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "myapp")]
struct Cli {
    #[command(subcommand)]
    command: MyCommands,
}

#[derive(Subcommand, Debug)]
enum MyCommands {
    Add{
        name: String,
        age: i32
    },
    Remove {
        id: u32
    },
    List,
    Start(StartCli)
}

// 使用 Args(作为“参数组”被展开)
#[derive(Args, Debug)]
struct StartCli {
    host: String,
    port: u32
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        MyCommands::Add { name, age } => {
            println!("添加: {} {}", name, age);
        }
        MyCommands::Remove { id } => {
            println!("删除 ID: {}", id);
        }
        MyCommands::List => {
            println!("列出所有");
        }
        MyCommands::Start(start_cli) => {
            println!("开始启动 {}-{}", start_cli.host, start_cli.port);
        }
    }
}

help内容

Usage: myapp <COMMAND>

Commands:
  add     
  remove  
  list    
  start   
  help    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

子命令add

target/debug/myapp add -h
Usage: myapp add <NAME> <AGE>

Arguments:
  <NAME>  
  <AGE>   

Options:
  -h, --help  Print help
  
# 用法
target/debug/myapp add Tom 32
添加: Tom 32

子命令remove

target/debug/myapp remove -h 
Usage: myapp remove <ID>

Arguments:
  <ID>  

Options:
  -h, --help  Print help

# 用法
target/debug/myapp remove 123
删除 ID: 123

子命令list

target/debug/myapp list -h   
Usage: myapp list

Options:
  -h, --help  Print help

# 用法
target/debug/myapp list   
列出所有

子命令start

target/debug/myapp start -h
Usage: myapp start <HOST> <PORT>

Arguments:
  <HOST>  
  <PORT>  

Options:
  -h, --help  Print help

# 用法
target/debug/myapp start 127.0.0.1 8080
开始启动 127.0.0.1-8080

选项参数

use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "myapp")]
struct Cli {
    #[command(subcommand)]
    command: MyCommands,
}

#[derive(Subcommand, Debug)]
enum MyCommands {
    Add{
        #[arg(short, long)]
        name: String,
        #[arg(short, long)]
        age: i32
    },
    Remove {
        #[arg(short, long)]
        id: u32
    },
    List,
    Start(StartCli)
}

#[derive(Args, Debug)]
struct StartCli {
    #[arg(long)]
    host: String,
    #[arg(long)]
    port: u32
}

fn main() {
    let cli = Cli::parse();

    match cli.command {
        MyCommands::Add { name, age } => {
            println!("添加: {} {}", name, age);
        }
        MyCommands::Remove { id } => {
            println!("删除 ID: {}", id);
        }
        MyCommands::List => {
            println!("列出所有");
        }
        MyCommands::Start(start_cli) => {
            println!("开始启动 {}-{}", start_cli.host, start_cli.port);
        }
    }
}

help内容

target/debug/myapp -h
Usage: myapp <COMMAND>

Commands:
  add     
  remove  
  list    
  start   
  help    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

子命令add

target/debug/myapp  add -h
Usage: myapp add --name <NAME> --age <AGE>

Options:
  -n, --name <NAME>  
  -a, --age <AGE>    
  -h, --help         Print help

# 用法
target/debug/myapp  add -n Bob -a 23
添加: Bob 23

子命令remove

target/debug/myapp  remove -h       
Usage: myapp remove --id <ID>

Options:
  -i, --id <ID>  
  -h, --help     Print help

# 用法
target/debug/myapp  remove -i 321
删除 ID: 321

子命令list


target/debug/myapp  list -h
Usage: myapp list

Options:
  -h, --help  Print help

# 用法
target/debug/myapp  list         
列出所有

子命令start

target/debug/myapp  start -h
Usage: myapp start --host <HOST> --port <PORT>

Options:
      --host <HOST>  
      --port <PORT>  
  -h, --help         Print help

# 用法
target/debug/myapp  start --host 127.0.0.1 --port 9090
开始启动 127.0.0.1-9090

子命令嵌套

二级子命令

``#[command(subcommand)]里面可以多个#[command(subcommand)]`

嵌套的子命令也需要是enum(选项),最后才是struct(参数)

说明

myapp docker start -x nginx
  │     │      │    │    │
  ▼     ▼      ▼    ▼    ▼
 应用  一级   二级  选项  值
       子命令 子命令

层级关系

myapp (Cli)                     ← 应用入口 [Parser]
  │
  └── tool: Tool (Subcommand)   ← 一级子命令
        │
        ├── Docker(DockerCmd)   ← 二级子命令入口 [有下级]
        │     │
        │     ├── Start         ← 叶子节点
        │     │     └── Args: image, name
        │     │
        │     └── Stop          ← 叶子节点
        │           └── Args: image_id, name (互斥)
        │
        └── Jenkins(JenkinsCmd) ← 二级子命令入口 [有下级]
              │
              ├── Start         ← 叶子节点
              │     └── Args: host, port
              │
              └── Stop          ← 叶子节点
                    └── Args: jenkins_id

嵌套规则

代码形态 使用的派生宏 代表含义
最外层 struct Cli #[derive(Parser)] 根命令(入口)
中间层 enum Tool / enum JenkinsCmd #[derive(Subcommand)] 子命令组(后面还要选一个动作)
最终层 内联字段或 struct Args #[derive(Args)](如果是单独的 struct) 具体的参数列表(叶子节点)

Subcommand嵌套规则

层级位置 类型 允许出现 #[command(subcommand)] 的次数
同一个 struct 内部 struct Cli 1 次(且只能 1 次)
枚举内部定义枚举 enum Tool 有多少个枚举值定义多少个#[command(subcommand)]
嵌套的下一层 enum DockerCmd 在 DockerCmd 的定义内部,如果它的变体是结构体,那个结构体里又能且只能有 1 次
嵌套的下一层 enum JenkinsCmd 同理

说明二级子命令

设置和command内容一样

// 简写(常用)
#[derive(Subcommand, Debug)]
enum DockerCmd {
    Start(DockerStartArg),
    Stop(DockerStopArg),
}

// 等价完整写法
#[derive(Subcommand, Debug)]
enum DockerCmd {
    #[command(name = "start")]   // 子命令名,默认就是变体名的小写
    Start(DockerStartArg),
    
    #[command(name = "stop")]
    Stop(DockerStopArg),
}

案例

use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "myapp")]
struct Cli {
    #[command(subcommand)]
    tool: Tool,
}

#[derive(Subcommand, Debug)]
enum Tool {
  	// DockerCmd 和 JenkinsCmd 是子命令枚举
  	// 都需要#[command(subcommand)]进行标注
    #[command(subcommand)]
    Docker(DockerCmd),
    #[command(subcommand)]
    Jenkins(JenkinsCmd),
}

// DockerCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum DockerCmd {
    Start(DockerStartArg),
    Stop(DockerStopArg),
}

// args可以参考clap的arg设置
#[derive(Args, Debug)]
struct DockerStartArg {
    #[arg(short = 'I')]
    image: String,
    #[arg(short = 'N')]
    name: String,
}

#[derive(Args, Debug)]
struct DockerStopArg {
    #[arg(short = 'I', long = "ID", conflicts_with = "name")]
    image_id: Option<String>,
    #[arg(short = 'N', conflicts_with = "image_id")]
    name: Option<String>,
}

// JenkinsCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum JenkinsCmd {
    Start(JenkinsStartArg),
    Stop(JenkinsStopArg),
}

#[derive(Args, Debug)]
struct JenkinsStartArg {
    #[arg(short = 'H')]
    host: String,
    #[arg(short = 'P')]
    port: i32,
}

#[derive(Args, Debug)]
struct JenkinsStopArg {
    #[arg(short = 'j')]
    jenkins_id: String,
}

fn main() {
    let cli = Cli::parse();
    match cli.tool {
        Tool::Docker(docker_cmd) => match docker_cmd {
            DockerCmd::Start(args) => {
                println!("docker run: {} {}", args.name, args.image);
            }
            DockerCmd::Stop(args) => {
                println!("docker stop: {:?} {:?}", args.image_id, args.name);
            }
        },
        Tool::Jenkins(jenkins_cmd) => match jenkins_cmd {
            JenkinsCmd::Start(args) => {
                println!("jenkins run: {} {}", args.host, args.port);
            }
            JenkinsCmd::Stop(args) => {
                println!("jenkins stop: {}", args.jenkins_id);
            }
        },
    }
}

help内容
target/debug/myapp  -h
Usage: myapp <COMMAND>

Commands:
  docker   
  jenkins  
  help     Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
使用方式
# Docker 子命令
target/debug/myapp docker start -I nginx -N web
target/debug/myapp docker stop -I abc123
target/debug/myapp docker stop -N web

# Jenkins 子命令
target/debug/myapp jenkins start -H localhost -P 8080
target/debug/myapp jenkins stop -j job-123

# 帮助
target/debug/myapp --help
target/debug/myapp docker --help
target/debug/myapp docker start --help
docker内部命令
########## 帮助信息 ##########
target/debug/myapp docker -h
Usage: myapp docker <COMMAND>

Commands:
  start  
  stop   
  help   Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help


########## start命令 ##########
target/debug/myapp docker start命令 -h
Usage: myapp docker start -I <IMAGE> -N <NAME>

Options:
  -I <IMAGE>  
  -N <NAME>   
  -h, --help  Print help

### 使用start
target/debug/myapp docker start -I postgres -N mypg
docker run: mypg postgres


########## stop命令 ##########
target/debug/myapp docker stop -h
Usage: myapp docker stop [OPTIONS]

Options:
  -I, --ID <IMAGE_ID>  
  -N <NAME>            
  -h, --help           Print help
  
### 使用stop
target/debug/myapp docker stop -I 1234        
docker stop: Some("1234") None

target/debug/myapp docker stop -N mypg
docker stop: None Some("mypg")
jenkins内部命令
########## 帮助信息 ##########
target/debug/myapp jenkins -h
Usage: myapp jenkins <COMMAND>

Commands:
  start  
  stop   
  help   Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help


########## start命令 ##########
target/debug/myapp jenkins start -h
Usage: myapp jenkins start -H <HOST> -P <PORT>

Options:
  -H <HOST>   
  -P <PORT>   
  -h, --help  Print help
  
### 使用start
target/debug/myapp jenkins start -H 127.0.0.1 -P 8989
jenkins run: 127.0.0.1 8989


########## stop命令 ##########
target/debug/myapp jenkins stop -h
Usage: myapp jenkins stop -j <JENKINS_ID>

Options:
  -j <JENKINS_ID>  
  -h, --help       Print help

### 使用stop
target/debug/myapp jenkins stop -j 8765
jenkins stop: 8765

三级子命令

说明

myapp docker image rm
  │     │      │    │
  ▼     ▼      ▼    ▼
 应用  一级   二级  三级
       子命令 子命令 子命令

层级关系

Cli (Parser)                    ← 应用入口
  └── tool: Tool (Subcommand)   ← 一级子命令
        ├── Docker(DockerCmd)   ← 二级子命令入口
        │     ├── Start(Args)   ← 叶子
        │     ├── Stop(Args)    ← 叶子
        │     └── Image(DockerImageCmd)  ← 三级子命令入口
        │           ├── Ls      ← 叶子
        │           ├── Rm(Args)← 叶子
        │           └── Inspect(Args) ← 叶子
        └── Xxxx(XxxxCmd) ← 其他模块

案例

use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "myapp", version="1.0.1", infer_subcommands=true, propagate_version=true)]
struct Cli {
    #[arg(short, long, global = true)]
    verbose: bool,
    #[command(subcommand)]
    tool: Tool,
}

#[derive(Subcommand, Debug)]
enum Tool {
    // DockerCmd 和 JenkinsCmd 是子命令枚举
    // 都需要#[command(subcommand)]进行标注
    #[command(subcommand)]
    Docker(DockerCmd)
}

// DockerCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum DockerCmd {
    Start(DockerStartArg),
    #[command(subcommand)]
    Image(DockerImageCmd)
}

#[derive(Args, Debug)]
struct DockerStartArg {
    #[arg(short = 'I')]
    image: String,
    #[arg(short = 'N')]
    name: String,
}

#[derive(Subcommand, Debug)]
enum DockerImageCmd {
    LS,
    RM,
    INSPECT
}

fn main() {
    let cli = Cli::parse();
    // 可以使用
    println!("verbose: {}", cli.verbose);
    match cli.tool {
        Tool::Docker(docker_cmd) => match docker_cmd {
            DockerCmd::Start(args) => {
                println!("docker run: {} {}", args.name, args.image);
            }
            DockerCmd::Image(images_cmd) => {
                match images_cmd {
                    DockerImageCmd::LS => {
                        println!("image: ls");
                    }
                    DockerImageCmd::RM => {
                        println!("image: rm");
                    }
                    DockerImageCmd::INSPECT => {
                        println!("image: inspect");
                    }
                }
            }
        }
    }
}
使用方式
target/debug/myapp docker image ls
target/debug/myapp docker image rm
target/debug/myapp docker image inspect

子命令继承

  • propagate_version = true子命令继承版本
  • infer_subcommands = true子命令简写
use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
// 设置propagate_version和infer_subcommands
#[command(name = "myapp", version="1.0.1", infer_subcommands=true, propagate_version=true)]
struct Cli {
    #[command(subcommand)]
    tool: Tool,
}

#[derive(Subcommand, Debug)]
enum Tool {
    // DockerCmd 和 JenkinsCmd 是子命令枚举
    // 都需要#[command(subcommand)]进行标注
    #[command(subcommand)]
    Docker(DockerCmd),
    #[command(subcommand)]
    Jenkins(JenkinsCmd),
}

// DockerCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum DockerCmd {
    Start(DockerStartArg),
    Stop(DockerStopArg),
}

#[derive(Args, Debug)]
struct DockerStartArg {
    #[arg(short = 'I')]
    image: String,
    #[arg(short = 'N')]
    name: String,
}

#[derive(Args, Debug)]
struct DockerStopArg {
    #[arg(short = 'I', long = "ID", conflicts_with = "name")]
    image_id: Option<String>,
    #[arg(short = 'N', conflicts_with = "image_id")]
    name: Option<String>,
}

// JenkinsCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum JenkinsCmd {
    Start(JenkinsStartArg),
    Stop(JenkinsStopArg),
}

#[derive(Args, Debug)]
struct JenkinsStartArg {
    #[arg(short = 'H')]
    host: String,
    #[arg(short = 'P')]
    port: i32,
}

#[derive(Args, Debug)]
struct JenkinsStopArg {
    #[arg(short = 'j')]
    jenkins_id: String,
}

fn main() {
    let cli = Cli::parse();
    match cli.tool {
        Tool::Docker(docker_cmd) => match docker_cmd {
            DockerCmd::Start(args) => {
                println!("docker run: {} {}", args.name, args.image);
            }
            DockerCmd::Stop(args) => {
                println!("docker stop: {:?} {:?}", args.image_id, args.name);
            }
        },
        Tool::Jenkins(jenkins_cmd) => match jenkins_cmd {
            JenkinsCmd::Start(args) => {
                println!("jenkins run: {} {}", args.host, args.port);
            }
            JenkinsCmd::Stop(args) => {
                println!("jenkins stop: {}", args.jenkins_id);
            }
        },
    }
}

# 支持简写,支持继承版本
target/debug/myapp d --version`
myapp-docker 1.0.1

target/debug/myapp j --version`
myapp-jenkins 1.0.1

子命令global用法

global = true 让参数在所有子命令层级都可用,不需要每层重复定义

use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "myapp", version="1.0.1", infer_subcommands=true, propagate_version=true)]
struct Cli {
    #[arg(short, long, global = true)]
    verbose: bool, // 设置共同参数
    #[command(subcommand)]
    tool: Tool,
}

#[derive(Subcommand, Debug)]
enum Tool {
    // DockerCmd 和 JenkinsCmd 是子命令枚举
    // 都需要#[command(subcommand)]进行标注
    #[command(subcommand)]
    Docker(DockerCmd),
    #[command(subcommand)]
    Jenkins(JenkinsCmd),
}

// DockerCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum DockerCmd {
    Start(DockerStartArg),
    Stop(DockerStopArg),
}

#[derive(Args, Debug)]
struct DockerStartArg {
    #[arg(short = 'I')]
    image: String,
    #[arg(short = 'N')]
    name: String,
}

#[derive(Args, Debug)]
struct DockerStopArg {
    #[arg(short = 'I', long = "ID", conflicts_with = "name")]
    image_id: Option<String>,
    #[arg(short = 'N', conflicts_with = "image_id")]
    name: Option<String>,
}

// JenkinsCmd 是二级子命令
#[derive(Subcommand, Debug)]
enum JenkinsCmd {
    Start(JenkinsStartArg),
    Stop(JenkinsStopArg),
}

#[derive(Args, Debug)]
struct JenkinsStartArg {
    #[arg(short = 'H')]
    host: String,
    #[arg(short = 'P')]
    port: i32,
}

#[derive(Args, Debug)]
struct JenkinsStopArg {
    #[arg(short = 'j')]
    jenkins_id: String,
}

fn main() {
    let cli = Cli::parse();
    // 可以使用
    println!("verbose: {}", cli.verbose);
    match cli.tool {
        Tool::Docker(docker_cmd) => match docker_cmd {
            DockerCmd::Start(args) => {
                println!("docker run: {} {}", args.name, args.image);
            }
            DockerCmd::Stop(args) => {
                println!("docker stop: {:?} {:?}", args.image_id, args.name);
            }
        },
        Tool::Jenkins(jenkins_cmd) => match jenkins_cmd {
            JenkinsCmd::Start(args) => {
                println!("jenkins run: {} {}", args.host, args.port);
            }
            JenkinsCmd::Stop(args) => {
                println!("jenkins stop: {}", args.jenkins_id);
            }
        },
    }
}
# 子命令也可以获取global的参数设置
target/debug/myapp docker start -I nginx -N web
verbose: false
docker run: web nginx

target/debug/myapp docker start -I nginx -N web -v
verbose: true
docker run: web nginx
posted @ 2026-08-10 00:14  lxd670  阅读(5)  评论(0)    收藏  举报