golang命令行和标志解析支持子命令插件库kingpin的使用
Golang 命令行和标志解析支持子命令插件库 Kingpin 的使用
Kingpin 是一个 Go 语言的命令行和标志解析库,支持流畅风格的 API 和类型安全的参数解析。它支持标志、嵌套命令和位置参数。
安装
$ go get github.com/alecthomas/kingpin/v2
简单示例
package main
import (
"fmt"
"github.com/alecthomas/kingpin/v2"
)
var (
verbose = kingpin.Flag("verbose", "Verbose mode.").Short('v').Bool()
name = kingpin.Arg("name", "Name of user.").Required().String()
)
func main() {
kingpin.Parse()
fmt.Printf("%v, %s\n", *verbose, *name)
}
复杂示例(支持子命令)
package main
import (
"os"
"strings"
"github.com/alecthomas/kingpin/v2"
)
var (
app = kingpin.New("chat", "A command-line chat application.")
debug = app.Flag("debug", "Enable debug mode.").Bool()
serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").IP()
register = app.Command("register", "Register a new user.")
registerNick = register.Arg("nick", "Nickname for user.").Required().String()
registerName = register.Arg("name", "Name of user.").Required().String()
post = app.Command("post", "Post a message to a channel.")
postImage = post.Flag("image", "Image to post.").File()
postChannel = post.Arg("channel", "Channel to post to.").Required().String()
postText = post.Arg("text", "Text to post.").Strings()
)
func main() {
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
// Register user
case register.FullCommand():
println(*registerNick)
// Post message
case post.FullCommand():
if *postImage != nil {
}
text := strings.Join(*postText, " ")
println("Post:", text)
}
}
主要特性
- 美观的帮助输出
- 可自定义的帮助模板
- 类型安全的标志和参数解析
- 支持任意深度的子命令
- 支持必需标志和必需位置参数
- 支持默认命令
- 每个命令、标志和参数的回调
- POSIX 风格的短标志组合
- 从文件读取命令行参数
- 自动生成 man 页面
- Bash/ZSH shell 自动补全
自定义解析器
Kingpin 支持自定义标志和位置参数的解析器。例如:
type HTTPHeaderValue http.Header
func (h *HTTPHeaderValue) Set(value string) error {
parts := strings.SplitN(value, ":", 2)
if len(parts) != 2 {
return fmt.Errorf("expected HEADER:VALUE got '%s'", value)
}
(*http.Header)(h).Add(parts[0], parts[1])
return nil
}
func (h *HTTPHeaderValue) String() string {
return ""
}
func HTTPHeader(s kingpin.Settings) (target *http.Header) {
target = &http.Header{}
s.SetValue((*HTTPHeaderValue)(target))
return
}
使用方式:
headers = HTTPHeader(kingpin.Flag("header", "Add a HTTP header to the request.").Short('H'))
重复标志
某些标志可以重复使用,这取决于它们持有的 Value
类型。Value
的 IsCumulative() bool
函数决定了是否可以多次调用 Set()
。
布尔值
布尔值在 Kingpin 中有特殊处理。每个布尔标志都有一个对应的否定标志:--<name>
和 --no-<name>
。
默认值
默认值是类型的零值。可以通过 Default(value...)
函数覆盖默认值。
Shell 自动补全
Kingpin 内置支持 Bash/ZSH shell 自动补全。可以通过以下方式生成补全脚本:
$ your-cli-tool --completion-script-bash
$ your-cli-tool --completion-script-zsh
自定义帮助
Kingpin 支持使用 Go 的 text/template
库自定义帮助输出。有四种内置模板:
kingpin.DefaultUsageTemplate
- 默认模板kingpin.CompactUsageTemplate
- 更紧凑的表示kingpin.SeparateOptionalFlagsUsageTemplate
- 将必需和可选标志分开kingpin.ManPageTemplate
- 用于生成 man 页面
示例:带子命令的 CLI 工具
package main
import (
"fmt"
"os"
"github.com/alecthomas/kingpin/v2"
)
var (
app = kingpin.New("myapp", "A command-line application.")
debug = app.Flag("debug", "Enable debug mode.").Bool()
serverAddr = app.Flag("server", "Server address.").Default("localhost:8080").String()
// Add command
addCmd = app.Command("add", "Add a new item.")
addItem = addCmd.Arg("item", "Item to add.").Required().String()
addForce = addCmd.Flag("force", "Force addition.").Short('f').Bool()
// Delete command
deleteCmd = app.Command("delete", "Delete an item.")
deleteItem = deleteCmd.Arg("item", "Item to delete.").Required().String()
deleteConfirm = deleteCmd.Flag("confirm", "Confirm deletion.").Short('y').Bool()
)
func main() {
cmd := kingpin.MustParse(app.Parse(os.Args[1:]))
fmt.Printf("Debug: %v\n", *debug)
fmt.Printf("Server: %s\n", *serverAddr)
switch cmd {
case addCmd.FullCommand():
fmt.Printf("Adding item: %s (force: %v)\n", *addItem, *addForce)
case deleteCmd.FullCommand():
fmt.Printf("Deleting item: %s (confirmed: %v)\n", *deleteItem, *deleteConfirm)
}
}
这个示例展示了如何创建一个支持子命令的 CLI 工具,包括全局标志、子命令特定的标志和参数。
更多关于golang命令行和标志解析支持子命令插件库kingpin的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang命令行和标志解析支持子命令插件库kingpin的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 命令行解析与 Kingpin 使用指南
在 Golang 中处理命令行参数时,标准库 flag
功能有限,而 kingpin
是一个强大的第三方库,特别适合构建复杂的命令行应用,支持子命令、参数验证、自动生成帮助文档等功能。
安装 Kingpin
go get gopkg.in/alecthomas/kingpin.v2
基础使用示例
package main
import (
"fmt"
"os"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
app = kingpin.New("myapp", "A command-line application.")
// 全局标志
debug = app.Flag("debug", "Enable debug mode.").Bool()
// 添加命令
addCmd = app.Command("add", "Add a new item.")
addCmdName = addCmd.Arg("name", "Item name.").Required().String()
// 删除命令
deleteCmd = app.Command("delete", "Delete an item.")
deleteCmdName = deleteCmd.Arg("name", "Item name.").Required().String()
)
func main() {
cmd := kingpin.MustParse(app.Parse(os.Args[1:]))
switch cmd {
case addCmd.FullCommand():
fmt.Printf("Adding item: %s (debug: %v)\n", *addCmdName, *debug)
case deleteCmd.FullCommand():
fmt.Printf("Deleting item: %s (debug: %v)\n", *deleteCmdName, *debug)
}
}
高级特性
1. 子命令嵌套
var (
app = kingpin.New("cli", "A complex CLI application.")
// 顶级命令
configCmd = app.Command("config", "Configuration management.")
// 子命令
configGetCmd = configCmd.Command("get", "Get configuration value.")
configGetKey = configGetCmd.Arg("key", "Configuration key.").Required().String()
configSetCmd = configCmd.Command("set", "Set configuration value.")
configSetKey = configSetCmd.Arg("key", "Configuration key.").Required().String()
configSetVal = configSetCmd.Arg("value", "Configuration value.").Required().String()
)
func main() {
cmd := kingpin.MustParse(app.Parse(os.Args[1:]))
switch cmd {
case configGetCmd.FullCommand():
fmt.Printf("Getting config: %s\n", *configGetKey)
case configSetCmd.FullCommand():
fmt.Printf("Setting config: %s=%s\n", *configSetKey, *configSetVal)
}
}
2. 参数验证
var (
app = kingpin.New("validate", "Demonstrates validation.")
port = app.Flag("port", "Port number.").
Short('p').
Default("8080").
Int()
file = app.Arg("file", "File to process.").
Required().
ExistingFile() // 验证文件存在
)
func main() {
kingpin.MustParse(app.Parse(os.Args[1:]))
fmt.Printf("Processing file %s on port %d\n", *file, *port)
}
3. 枚举选项
var (
app = kingpin.New("enum", "Demonstrates enum flags.")
logLevel = app.Flag("log-level", "Logging level.").
Default("info").
Enum("debug", "info", "warn", "error")
)
func main() {
kingpin.MustParse(app.Parse(os.Args[1:]))
fmt.Printf("Log level: %s\n", *logLevel)
}
4. 自定义解析器
type HostPort struct {
Host string
Port int
}
func (h *HostPort) Set(value string) error {
parts := strings.Split(value, ":")
if len(parts) != 2 {
return fmt.Errorf("expected host:port")
}
h.Host = parts[0]
var err error
h.Port, err = strconv.Atoi(parts[1])
return err
}
func (h *HostPort) String() string {
return fmt.Sprintf("%s:%d", h.Host, h.Port)
}
func HostPortParser(s kingpin.Settings) (target *HostPort) {
target = &HostPort{}
s.SetValue(target)
return
}
var (
app = kingpin.New("custom", "Demonstrates custom parsers.")
endpoint = app.Flag("endpoint", "Server endpoint.").
PlaceHolder("HOST:PORT").
Required().
SetValue(&HostPort{})
)
func main() {
kingpin.MustParse(app.Parse(os.Args[1:]))
fmt.Printf("Connecting to %s:%d\n", endpoint.Host, endpoint.Port)
}
最佳实践
- 命令组织:将相关命令组织到子命令中,保持层次清晰
- 参数验证:尽可能在解析阶段验证参数,而不是在业务逻辑中
- 帮助文档:为每个命令和参数添加有意义的描述
- 默认值:为常用参数设置合理的默认值
- 错误处理:使用
kingpin.MustParse
简化错误处理
与标准库 flag 对比
特性 | flag | kingpin |
---|---|---|
子命令支持 | 有限 | 完善 |
参数验证 | 无 | 强大 |
帮助生成 | 基础 | 自动美化 |
类型支持 | 基础 | 丰富 |
学习曲线 | 简单 | 中等 |
Kingpin 特别适合构建复杂的 CLI 工具,而标准库 flag 更适合简单的命令行参数解析需求。
希望这个指南能帮助你快速上手 kingpin 库!