[TOC]
Cobra 是一个用于创建强大的现代 CLI 应用程序的库。
Cobra 用于许多 Go 项目,例如 Kubernetes、Hugo 和 GitHub CLI 等。 此列表包含更广泛的使用 Cobra 的项目列表。
Cobra提供:
- 基于简单子命令的 CLI:应用程序服务器、应用程序获取等。
- 完全符合 POSIX 标准的标志(包括短版本和长版本)
- 嵌套子命令
- 全局、局部和级联标志
- 智能建议(应用程序服务器...您是指应用程序服务器吗?)
- 自动生成命令和标志的帮助
- 子命令的分组帮助
- 自动帮助标志识别 -h、--help 等。
- 为您的应用程序自动生成 shell 自动完成功能(bash、zsh、fish、powershell)
- 为您的应用程序自动生成手册页
- 命令别名,以便您可以在不破坏它们的情况下进行更改
- 灵活定义您自己的帮助、用法等。
- 可选与 viper 无缝集成
# 概念
Cobra 建立在命令(Commands)、参数(args)和标志(flags)的结构之上。
命令(Commands):代表动作
标志(flags):这些动作的修饰符
参数(args):事物
# 用户指南
要手动实现 Cobra,您需要创建一个裸 main.go 文件和一个 rootCmd 文件。 您可以选择提供您认为合适的其他命令。
## 基本的cobra示例(根命令)
1. 初始项目
```shell
$ go mod init [项目名称]
$ go get -u github.com/spf13/cobra
```
2. 创建rootCmd
您将其放置在 `./cmd/root.go` 中:
```go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
// 命令名字
Use: "mytools",
// 简短描述,体现到 `Available Commands` 的说明。
// 注意:根目录不起作用
Short: "personnel management system",
// 详细描述,体现到帮助文档的第一行信息
Long: "You can view/modify personnel information through mytools",
// 版本号
Version: "1.1.0",
// 命令处理业务逻辑
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("hello world")
},
}
// Execute 是命令的入口点
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Printf("err: %v\n", err)
}
}
```
3. 创建main.go
您将其放置在 ./mian.go 中:
```go
package main
import (
"cobra/cmd"
)
func main() {
cmd.Execute()
}
```
4. 运行情况
```shell
# 执行命令
$ go run main.go
hello world
# 查看帮助文档
$ go run main.go -h
You can view/modify personnel information through mytools
Usage:
mytools [flags]
Flags:
-h, --help help for mytools
-v, --version version for mytools
# 查看版本信息
$ go run main.go -v
mytools version 1.1.0
```
## 子命令
1. 您将其放置在 `./cmd/add.go` 用下面的代码填充它:
```go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
func init() {
// 在rootCmd下添加子命令
rootCmd.AddCommand(addCmd)
}
var addCmd = &cobra.Command{
Use: "add",
Short: "Add personnel",
Long: "Add class personnel information",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Add personnel")
},
}
```
2. 运行情况
```bash
# 查看帮助文档
## 1. 根命令帮助文档
$ go run main.go -h
You can view/modify personnel information through mytools
Usage:
mytools [flags]
mytools [command]
Available Commands:
add Add personnel
completion Generate the autocompletion script for the specified shell
help Help about any command
Flags:
-h, --help help for mytools
-v, --version version for mytools
Use "mytools [command] --help" for more information about a command.
## 2. add子命令的帮助文档
$ go run main.go add -h
Add class personnel information
Usage:
mytools add [flags]
Flags:
-h, --help help for add
# 执行add子命令
$ go run main.go add
Add personnel
```
## 子命令别名
1. 在 `cobra.Command` 结构体添加 `Aliases` 字段信息, 例如在 `./cmd/add.go` 文件添加aliases字段
```go
Aliases: []string{"create"},
```
2. 运行情况
```bash
# 查看帮助文档
$ go run main.go create -h
Add class personnel information
Usage:
mytools add [flags]
Aliases:
add, create
Flags:
-h, --help help for add
# 执行create别名
$ go run main.go create
Add personnel
```
## flags标志
标志提供了修饰符来控制操作命令的操作方式,分为 本地标志 和 全局标志
1. 本地标志
语法:命令结构体.Flags().typeVarP(&变量名, 长参数, 短参数, 默认值, 参数说明)
```go
func init() {
// 在rootCmd下添加子命令
rootCmd.AddCommand(addCmd)
// 在addCmd添加本地标志(addCmd.Flags)
// 作用范围:只有addCmd才能使用
addCmd.Flags().StringVarP(&name, "name", "n", "", "Your name")
}
```
效果展示
```bash
# 查看帮助文档
$ go run main.go add -h
Add class personnel information
Usage:
mytools add [flags]
Aliases:
add, create
Flags:
-h, --help help for add
-n, --name string Your name
```
2. 全局标志
语法:命令结构体.PersistentFlags().typeVarP(&变量名, 长参数, 短参数, 默认值, 参数说明)
```go
func init() {
// 在rootCmd下添加子命令
rootCmd.AddCommand(addCmd)
// 在addCmd添加全局标志(addCmd.Flags)
// 作用范围:addCmd及addCmd子命令下都生效
addCmd.PersistentFlags().Int8VarP(&age, "age", "a", 0, "Your age")
}
```
效果展示
```bash
# 查看add帮助文档
$ go run main.go add -h
Add class personnel information
Usage:
mytools add [flags]
Aliases:
add, create
Flags:
-a, --age int8 Your age
-h, --help help for add
# 查看add的子命令帮助文档
$ go run main.go add test -h
Usage:
mytools add test [flags]
Flags:
-h, --help help for test
Global Flags:
-a, --age int8 Your age
```
3. 必传flag标志
语法:命令结构体.MarkFlagRequired("长参数")
```go
func init() {
// 在rootCmd下添加子命令
rootCmd.AddCommand(addCmd)
addCmd.Flags().StringVarP(&name, "name", "n", "", "Your name")
// flags为name是必传项,name是要在命令结构体的flag标志(本地和全局都行)
addCmd.MarkFlagRequired("name")
}
```
效果展示
```bash
$ go run main.go add
Error: required flag(s) "name" not set
Usage:
mytools add [flags]
mytools add [command]
Aliases:
add, create
Available Commands:
test
Flags:
-h, --help help for add
-n, --name string Your name
Use "mytools add [command] --help" for more information about a command.
err: required flag(s) "name" not set
```
>[info] 没有 `name` 的flags标志位,报错信息提示在第一行与最后一行。中间都是帮助文档,提示不够简单明了。当然可以把中间的帮助信息屏蔽掉
解决方案:在 `命令结构体` 添加 `SilenceUsage` 参数
```go
// 在发生错误,不输出帮助信息
SilenceUsage: true,
```
4. flags组合
语法:命令结构体.MarkFlagsRequiredTogether([]string{"长参数1", "长参数2"}...)
```go
func init() {
// 在rootCmd下添加子命令
rootCmd.AddCommand(addCmd)
// name和age绑定为一个组,两个参数必须同时出现或都不出现。
addCmd.MarkFlagsRequiredTogether([]string{"name", "age"}...)
}
```
效果展示
```bash
# 不加上述绑定组的标志位
$ go run main.go add
Add personnel
# 添加其中一个
$ go run main.go add -n jiaxzeng
Error: if any flags in the group [name age] are set they must all be set; missing [age]
err: if any flags in the group [name age] are set they must all be set; missing [age]
# flag组内的参数都添加
$ go run main.go add -n jiaxzeng -a 18
Add personnel
```
## args参数
除了命令及flags标志之外,都匹配到args参数.
>info args参数获取不需要任何代码,下面代码是复用add的子命令
```go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
name string
age int8
)
func init() {
// 在rootCmd下添加子命令
rootCmd.AddCommand(addCmd)
// 在addCmd添加本地标志(addCmd.Flags)
// 作用范围:只有addCmd才能使用
addCmd.Flags().StringVarP(&name, "name", "n", "", "Your name")
// 在addCmd添加全局标志(addCmd.Flags)
// 作用范围:addCmd及addCmd子命令下都生效
addCmd.PersistentFlags().Int8VarP(&age, "age", "a", 0, "Your age")
// name是flags必传项
addCmd.MarkFlagRequired("name")
// name和age是捆绑项,要么一起出现,要么都不出现
addCmd.MarkFlagsRequiredTogether([]string{"name", "age"}...)
}
var addCmd = &cobra.Command{
Use: "add",
Aliases: []string{"create"},
Short: "Add personnel",
Long: "Add class personnel information",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Add personnel")
},
SilenceUsage: true,
}
```
效果演示
```bash
# 不传任何flag标志
$ go run main.go add ls wd
Add personnel
name: , age: 0, args: [ls wd]
# args可以放在随意的位置
$ go run main.go add -n jiaxzeng kjflsd -a 18
Add personnel
name: jiaxzeng, age: 18, args: [kjflsd]
$ go run main.go add fljkew -n jiaxzeng -a 18
Add personnel
name: jiaxzeng, age: 18, args: [fljkew]
$ go run main.go add -n jiaxzeng -a 18 fjklsd
Add personnel
name: jiaxzeng, age: 18, args: [fjklsd]
$ go run main.go add -n jiaxzeng kdl fdkls -a 18 fjk
Add personnel
name: jiaxzeng, age: 18, args: [kdl fdkls fjk]
```
## 自定义帮助文档(-h, --help)
```go
package cmd
import (
"github.com/spf13/cobra"
)
var getCmdHelp string = `
This is test help doc.
`
func init() {
rootCmd.AddCommand(getCmd)
// 自定义帮助文档
getCmd.SetHelpTemplate(getCmdHelp)
}
var getCmd = &cobra.Command{
Use: "get",
Short: "get personnel",
Long: "get class personnel information",
Run: func(cmd *cobra.Command, args []string) {
},
}
```
演示效果
```bash
# 查看帮助文档1
$ go run main.go get -h
This is test help doc.
# 查看帮助文档2
$ go run main.go get --help
This is test help doc.
```
## 未传参数和flags,打印帮助文档
>[info] flags没有设置必传项,不传任何信息都可以执行命令,这种不太符合使用习惯。一般习惯是不传任何参数的时候,希望输出命令或子命令的帮助文档。
在 命令结构体 的 `Run` 字段判断下参数即可
```go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(getCmd)
getCmd.Flags().StringVarP(&name, "name", "n", "", "Your name")
getCmd.Flags().Int8VarP(&age, "age", "a", 0, "Your age")
}
var getCmd = &cobra.Command{
Use: "get",
Short: "get personnel",
Long: "get class personnel information",
Run: func(cmd *cobra.Command, args []string) {
// 判断是否有传args与flags标志位
// 判断成功则查看帮助文档,如果失败则执行命令
if len(args) == 0 && (name == "" && age == int8(0)) {
cmd.Help()
} else {
fmt.Printf("name: %v, age: %v\n", name, age)
}
},
}
```
效果演示
```bash
# 不带args和flags标志位
$ go run main.go get
get class personnel information
Usage:
mytools get [flags]
Flags:
-a, --age int8 Your age
-h, --help help for get
-n, --name string Your name
# 带上flags标志
$ go run main.go get -n jiaxzeng -a 18
name: jiaxzeng, age: 18
# 带上args
$ go run main.go get 123
name: , age: 0
```
# 补全命令
```shell
source <(kvmmanager completion bash)
```
> 依赖于宿主机有安装 `bash-completion` 包,需要重新登录用户
# 在线文档
Golang pkg:https://pkg.go.dev/github.com/spf13/cobra
GitHub:https://github.com/spf13/cobra
- Golang简介
- 开发环境
- Golang安装
- 编辑器及快捷键
- vscode插件
- 第一个程序
- 基础数据类型
- 变量及匿名变量
- 常量与iota
- 整型与浮点型
- 复数与布尔值
- 字符串
- 运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 流程控制语句
- 获取用户输入
- if分支语句
- for循环语句
- switch语句
- break_continue_goto语法
- 高阶数据类型
- pointer指针
- array数组
- slice切片
- slice切片扩展
- map映射
- 函数
- 函数定义和调用
- 函数参数
- 函数返回值
- 作用域
- 函数形参传递
- 匿名函数
- 高阶函数
- 闭包
- defer语句
- 内置函数
- fmt
- strconv
- strings
- time
- os
- io
- 文件操作
- 编码
- 字符与字节
- 字符串
- 读写文件
- 结构体
- 类型别名和自定义类型
- 结构体声明
- 结构体实例化
- 模拟构造函数
- 方法接收器
- 匿名字段
- 嵌套与继承
- 序列化
- 接口
- 接口类型
- 值接收者和指针接收者
- 类型与接口对应关系
- 空接口
- 接口值
- 类型断言
- 并发编程
- 基本概念
- goroutine
- channel
- select
- 并发安全
- 练习题
- 第三方库
- Survey
- cobra