如何用Groovy实现类似kubectl的两级CLI命令菜单?
在Groovy中实现两级CLI子命令结构
方案1:嵌套使用CliBuilder
虽然CliBuilder本身不直接支持多级命令,但可以通过嵌套实例化CliBuilder模拟子命令结构。核心逻辑是先解析顶级命令,再根据结果加载对应子命令的解析器。
示例代码
def cli = new CliBuilder(usage: 'myCli [command] [command options]') cli.with { h longOpt: 'help', '显示帮助信息' v longOpt: 'version', '显示版本信息' } def options = cli.parse(args) if (!options) return // 处理全局选项 if (options.h) { cli.usage() println "\ncommands:" println "command1 Command 1 description" println "command2 Command 2 description" println "help Help on a command" println "version Show version info" return } if (options.v) { println "myCli v1.0.0" return } // 提取子命令与子参数 def subCommand = options.arguments()[0] def subArgs = options.arguments()[1..-1] // 分发处理子命令 switch(subCommand) { case 'command1': def cmd1Cli = new CliBuilder(usage: 'myCli command1 [options]') cmd1Cli.a '选项A的描述' cmd1Cli.b longOpt: 'bar', '选项B的描述' def cmd1Opts = cmd1Cli.parse(subArgs) if (!cmd1Opts) return println "执行command1,选项A: ${cmd1Opts.a}, 选项B: ${cmd1Opts.b}" break case 'command2': def cmd2Cli = new CliBuilder(usage: 'myCli command2 [options]') cmd2Cli.c longOpt: 'config', args:1, '配置文件路径' def cmd2Opts = cmd2Cli.parse(subArgs) if (!cmd2Opts) return println "执行command2,配置文件: ${cmd2Opts.c}" break case 'help': if (subArgs) { switch(subArgs[0]) { case 'command1': new CliBuilder(usage: 'myCli command1 [options]').usage() break case 'command2': new CliBuilder(usage: 'myCli command2 [options]').usage() break default: println "未知命令: ${subArgs[0]}" } } else { cli.usage() println "\ncommands:" println "command1 Command 1 description" println "command2 Command 2 description" println "help Help on a command" println "version Show version info" } break case 'version': println "myCli v1.0.0" break default: println "未知命令: ${subCommand}" cli.usage() return }
方案2:使用Picocli(推荐)
如果觉得嵌套CliBuilder不够优雅,可选用Picocli——这是专门支持多级命令的Java/Groovy CLI库,语法简洁、功能完善。
示例代码
首先引入依赖(以Gradle为例):
implementation 'info.picocli:picocli:4.6.3'
然后编写命令类:
import picocli.CommandLine import picocli.CommandLine.Command import picocli.CommandLine.Option @Command(name = "myCli", description = "自定义Groovy CLI工具", subcommands = [Command1.class, Command2.class, CommandLine.HelpCommand.class, VersionCommand.class]) class MyCli { @Option(names = ["-h", "--help"], usageHelp = true, description = "显示帮助信息") boolean helpRequested @Option(names = ["-v", "--version"], versionHelp = true, description = "显示版本信息") boolean versionRequested static void main(String[] args) { int exitCode = new CommandLine(new MyCli()).execute(args) System.exit(exitCode) } } @Command(name = "command1", description = "Command 1 description") class Command1 implements Runnable { @Option(names = ["-a"], description = "选项A的描述") boolean a @Option(names = ["-b", "--bar"], description = "选项B的描述") String b @Override void run() { println "执行command1,选项A: ${a}, 选项B: ${b}" } } @Command(name = "command2", description = "Command 2 description") class Command2 implements Runnable { @Option(names = ["-c", "--config"], description = "配置文件路径", required = true) String configPath @Override void run() { println "执行command2,配置文件: ${configPath}" } } @Command(name = "version", description = "Show version info") class VersionCommand implements Runnable { @Override void run() { println "myCli v1.0.0" } }
Picocli的优势
- 原生支持多级子命令,无需手动处理参数分发
- 自动生成符合kubectl风格的规范usage信息
- 内置选项验证、类型转换、彩色输出等高级功能
- 适配Groovy简洁语法,代码可读性高
内容的提问来源于stack exchange,提问作者Lawrence Zeng
相关产品推荐
相关产品推荐

