golang极简但功能强大的命令行工具插件库mcli的使用
golang极简但功能强大的命令行工具插件库mcli的使用
mcli是一个极简但功能强大的Go语言命令行库。"m"代表minimal(极简)和magic(魔法)。
特性
- 简单易用,API简洁但功能强大,可以轻松定义命令、标志和参数
- 只需一行代码即可添加任意嵌套的子命令
- 在帮助信息中将子命令分组到不同类别
- 使用结构体标签在命令处理器内部定义命令标志和参数
- 定义适用于所有命令的全局标志,或在命令组之间共享通用标志
- 从环境变量读取标志和参数值
- 为标志和参数设置默认值
- 开箱即用地支持time.Duration、slice和map类型
- 可以标记命令和标志为隐藏,隐藏的命令和标志不会显示在帮助中
- 可以标记标志和参数为必需项,当缺少必需标志时会报错
- 可以标记标志为已弃用
- 类似git的自动建议功能
- 自动为命令、标志和参数生成帮助信息
- 自动识别帮助标志如
-h
、--help
等 - 自动shell补全,支持bash、zsh、fish和powershell
- 兼容标准库的flag.FlagSet
- 可选支持posix风格的单令牌多选项命令行解析
- 命令别名功能,可以重组命令而不会破坏现有命令
- 灵活定义自定义用法消息
- 依赖极少
- 让你爱上用Go编写命令行程序
基本用法
在main函数中使用:
func main() {
var args struct {
Name string `cli:"-n, --name, Who do you want to say to" default:"tom"`
// 这个参数是必需的
Text string `cli:"#R, text, The 'message' you want to send"`
// 这个参数从环境变量读取,且要求变量必须存在
// 它不接受命令行输入
APIAccessKey string `cli:"#ER, The access key to your service provider" env:"MY_API_ACCESS_KEY"`
}
mcli.Parse(&args)
fmt.Printf("Say to %s: %s\n", args.Name, args.Text)
}
运行示例:
$ go run say.go -h
Usage:
say [flags] <text>
Flags:
-n, --name <string> Who do you want to say to
[default: "tom"]
Arguments:
text <message> [REQUIRED] The message you want to send
Environment Variables:
- MY_API_ACCESS_KEY <string> [REQUIRED]
The access key to your service provider
$ MY_API_ACCESS_KEY=xxxx go run say.go hello
Say to tom: hello
使用子命令
func main() {
mcli.Add("cmd1", runCmd1, "An awesome command cmd1")
mcli.AddGroup("cmd2", "This is a command group called cmd2")
mcli.Add("cmd2 sub1", runCmd2Sub1, "Do something with cmd2 sub1")
mcli.Add("cmd2 sub2", runCmd2Sub2, "Brief description about cmd2 sub2")
// 也可以不注册组直接添加子命令
mcli.Add("group3 sub1 subsub1", runGroup3Sub1Subsub1, "Blah blah Blah")
// 这是一个隐藏命令,不会显示在帮助中
// 除非指定了--mcli-show-hidden标志
mcli.AddHidden("secret-cmd", secretCmd, "An secret command won't be showed in help")
// 启用shell自动补全
mcli.AddCompletion()
mcli.Run()
}
func runCmd1() {
var args struct {
Branch string `cli:"-b, --branch, Select another branch by passing in the branch name"`
Commit bool `cli:"-c, --commit, Open the last commit"`
NoBrowser bool `cli:"-n, --no-browser, Print destination URL instead of opening the browser"`
Projects bool `cli:"-p, --projects, Open repository projects"`
Repo string `cli:"-R, --repo, Select another repository using the '[HOST/]OWNER/REPO' format"`
Settings bool `cli:"-s, --settings, Open repository settings"`
Wiki bool `cli:"-w, --wiki, Open repository wiki"`
Location string `cli:"location, A browser location can be specified using arguments in the following format:\n- by number for issue or pull request, e.g. \"123\"; or\n- by path for opening folders and files, e.g. \"cmd/gh/main.go\""`
}
mcli.Parse(&args)
// 执行操作
}
type Cmd2CommonArgs struct {
Repo string `cli:"-R, --repo, Select another repository using the '[HOST/]OWNER/REPO' format"`
}
func runCmd2Sub1() {
// 注意标志/参数描述可以用逗号或空格分隔,也可以混合使用
var args struct {
Body string `cli:"-b, --body Supply a body. Will prompt for one otherwise."`
BodyFile string `cli:"-F, --body-file Read body text from 'file' (use \"-\" to read from standard input)"`
Editor bool `cli:"-e, --editor, Add body using editor"`
Web bool `cli:"-w, --web, Add body in browser"`
// 可以嵌入其他结构体
Cmd2CommonArgs
}
mcli.Parse(&args)
// 执行操作
}
API
使用默认App:
SetOptions
- 更新默认应用程序的选项SetGlobalFlags
- 设置全局标志,全局标志对所有命令可用Add
- 添加一个命令AddRoot
- 添加根命令,当没有指定子命令时执行AddAlias
- 为命令添加别名AddHidden
- 添加隐藏命令AddGroup
- 显式添加组AddHelp
- 启用"help"命令AddCompletion
- 启用"completion"命令生成自动补全脚本Parse
- 解析命令行的标志和参数Run
- 运行程序,解析命令行,查找并运行注册的命令PrintHelp
- 打印当前命令的使用文档到stderr
创建新的App实例:
NewApp
- 创建新的cli应用程序实例
标签语法
结构体标签是Go的一个强大特性,mcli
使用结构体标签来定义标志和参数。
cli
标签定义标志和参数的名称和描述env
标签可选地告诉Parse从环境变量查找值default
标签可选地为标志或参数提供默认值
语法:
/* cli标签,只有Name是必需的
* 短名称和长名称都是可选的,但至少需要提供一个
* 例如:
* - `cli:"-c, Open the last commit"`
* - `cli:"#R, -b, --branch, Select another branch by passing in the branch name"`
* - `cli:"--an-obvious-flag-dont-need-description"`
* - `cli:"#ER, AWS Secret Access Key" env:"AWS_SECRET_ACCESS_KEY"`
*/
CliTag <- ( Modifiers ',' Space? )? Name ( ( ',' | Space ) Description )?
Modifiers <- '#' [DHRE]+
Name <- ( ShortName LongName? ) | LongName
Description <- ( ![\r\n] . )*
/* env标签,可选
* 可以指定多个环境变量名,第一个非空值生效
* 例如:
* - `env:"SOME_ENV"`
* - `env:"ANOTHER_ENV_1, ANOTHER_ENV_2"`
*/
EnvTag <- ( EnvName ',' Space? )* EnvName
/* 默认值标签,可选
* 例如:
* - `default:"1.5s"` // 持续时间
* - `default:"true"` // 布尔值
*/
DefaultValueTag <- ( ![\r\n] . )*
修饰符
修饰符表示标志的选项,可以将标志标记为已弃用、隐藏或必需。在cli
标签中,修饰符出现在第一个段,以#
字符开头。
目前可用的修饰符:
- D - 将标志或参数标记为已弃用,"DEPRECATED"将显示在帮助中
- R - 将标志或参数标记为必需,"REQUIRED"将显示在帮助中
- H - 将标志标记为隐藏
- E - 标记参数从环境变量读取,而不是命令行
兼容标准flag包
Parse
成功时返回一个*flag.FlagSet
,所有定义的标志都可以通过flag set访问,包括短名称和长名称。
Shell补全
mcli
支持bash、zsh、fish和powershell的自动shell补全。使用AddCompletion
启用该功能,运行program help completion [bash|zsh|fish|powershell]
获取使用指南。
更多关于golang极简但功能强大的命令行工具插件库mcli的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang极简但功能强大的命令行工具插件库mcli的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
mcli - Go语言极简命令行工具插件库
mcli 是一个轻量级但功能强大的 Go 语言命令行工具开发库,它提供了简洁的 API 来快速构建命令行应用。以下是 mcli 的主要特性和使用示例。
主要特性
- 极简 API 设计
- 支持子命令和嵌套子命令
- 自动生成帮助信息
- 支持多种参数类型
- 内置参数验证
- 插件式架构
安装
go get github.com/yourusername/mcli
基础使用示例
package main
import (
"fmt"
"github.com/yourusername/mcli"
)
func main() {
app := mcli.NewApp("myapp", "A simple CLI application")
app.AddCommand("greet", "Greet someone", func(name string, times int) {
for i := 0; i < times; i++ {
fmt.Printf("Hello, %s!\n", name)
}
})
app.Run()
}
运行:
$ go run main.go greet John 3
Hello, John!
Hello, John!
Hello, John!
进阶功能
1. 子命令嵌套
app := mcli.NewApp("fileutil", "File utility tool")
// 添加子命令
fileCmd := app.AddSubCommand("file", "File operations")
// 在子命令下再添加子命令
fileCmd.AddCommand("copy", "Copy a file", func(src, dest string) {
fmt.Printf("Copying from %s to %s\n", src, dest)
// 实现复制逻辑
})
fileCmd.AddCommand("delete", "Delete a file", func(path string) {
fmt.Printf("Deleting file: %s\n", path)
// 实现删除逻辑
})
app.Run()
2. 参数类型支持
mcli 自动支持多种参数类型:
app.AddCommand("example", "Show parameter types",
func(
s string,
i int,
f float64,
b bool,
slice []string,
) {
fmt.Printf("String: %s\n", s)
fmt.Printf("Int: %d\n", i)
fmt.Printf("Float: %f\n", f)
fmt.Printf("Bool: %t\n", b)
fmt.Printf("Slice: %v\n", slice)
})
3. 选项参数 (Flags)
app.AddCommand("search", "Search for something", func() {
var (
query string
limit int
verbose bool
)
mcli.Flag(&query, "query", "q", "Search query")
mcli.Flag(&limit, "limit", "l", 10, "Result limit")
mcli.Flag(&verbose, "verbose", "v", false, "Verbose output")
mcli.Parse()
fmt.Printf("Searching for '%s' with limit %d (verbose: %t)\n",
query, limit, verbose)
})
4. 参数验证
app.AddCommand("useradd", "Add a user", func(username string, age int) {
mcli.Validate(func() error {
if len(username) < 3 {
return fmt.Errorf("username must be at least 3 characters")
}
if age < 18 {
return fmt.Errorf("user must be at least 18 years old")
}
return nil
})
fmt.Printf("Added user %s (age %d)\n", username, age)
})
5. 插件系统
创建插件:
// greeter.go
package greeter
import "github.com/yourusername/mcli"
func init() {
mcli.RegisterPlugin("greeter", func(app *mcli.App) {
app.AddCommand("hello", "Say hello", func() {
fmt.Println("Hello from plugin!")
})
})
}
主程序加载插件:
package main
import (
_ "./greeter" // 导入插件
"github.com/yourusername/mcli"
)
func main() {
app := mcli.NewApp("myapp", "App with plugins")
app.LoadPlugins()
app.Run()
}
最佳实践
- 命令组织:将相关命令组织到子命令中
- 错误处理:使用 Validate 进行参数验证
- 插件化:将功能模块化为插件以便复用
- 文档:为每个命令提供清晰的描述
- 测试:为 CLI 命令编写测试
性能考虑
mcli 设计时考虑了性能:
- 延迟初始化:只在需要时解析参数
- 零反射:尽可能避免使用反射
- 内存高效:最小化内存分配
与其他库对比
相比 cobra 和 urfave/cli:
- 更简单的 API
- 更少的依赖
- 更快的启动时间
- 更适合小型到中型 CLI 应用
mcli 是构建 Go 命令行工具的轻量级选择,特别适合需要快速开发且保持代码简洁的项目。