Cobra 简介
Cobra 是一个流行的 Go
语言库,用于创建强大且灵活的命令行应用程序。它由 spf13
开发,设计用于与 Go 生态系统中的其他流行库(如 Viper
配置库)无缝集成。Cobra
支持多级命令结构,允许定义根命令和任意数量的子命令,还可以轻松处理全局和本地标志。它自动生成帮助和使用信息,并支持 Bash
、Zsh
、Fish
和 PowerShell
的命令补全。此外,Cobra
能够生成 Markdown
格式的文档,使文档维护更加便捷。通过与 Viper
集成,Cobra
能处理配置文件和环境变量,为开发者提供了强大的工具集,使创建复杂的 Client
工具变得简单高效。Cobra
广泛应用于各种 Go 项目中,提升了 Client
应用的开发体验和维护效率。
下面是 Cobra
主要的功能:
支持多级命令结构:轻松定义根命令和任意数量的子命令,组织复杂的命令行应用。
处理全局和本地标志:解析和处理命令行参数,支持全局标志和局部标志。
自动生成帮助和使用信息:根据命令和标志自动生成详细的帮助和使用信息。
支持命令补全:提供 Bash、Zsh、Fish 和 PowerShell 的命令补全脚本,提升用户体验。
生成 Markdown 格式的文档:自动生成命令行工具的 Markdown 格式文档,方便文档维护。
Cobra 的使用非常广泛,特别是在云原生和 DevOps 工具中。下面是使用 Cobra
构建 CLI
工具的知名工具:
Kubernetes (k8s):这个流行的容器编排平台的命令行工具 kubectl 就是使用 Cobra 构建的。
Docker:Docker CLI 也是基于 Cobra 开发的。
Hugo:这个流行的静态网站生成器使用 Cobra 来构建其命令行界面。
GitHub CLI:GitHub 的官方命令行工具 gh 也使用了 Cobra。
CoreDNS:这个灵活可扩展的 DNS 服务器使用 Cobra 来管理其命令行接口。
下面让我们一起进入正题,Cobra
上手教程。
Cobra 上手教程
第一步我们要创建一个项目,然后为项目安装 Cobra
:
go get -u github.com/spf13/cobra@latest
我们在 main.go
中添加如下代码来创建第一个命令行工具:
package main
import (
"fmt"
"github.com/spf13/cobra" "log")
func main() {
funCmd := &cobra.Command{
Use: "fun",
Short: "Demo of Cobra,打印 FunTester !!!",
Long: "Demo of Cobra,打印 FunTester !!!,使用Cobra构建命令行工具,实现简单的命令行功能",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, FunTester!")
},
}
if err := funCmd.Execute(); err != nil {
log.Fatal(err)
}
}
复制代码
这是参数的解释:
Use: 命令的使用方法,通常是命令的名称。
Short: 简短描述,在帮助信息中显示。
Long: 详细描述,在帮助信息中显示。
Run: 命令执行时的函数。
我们本地编译执行 ./funtester
,控制台就会打印
接收参数
在 Cobra
中,处理命令行参数是构建命令行应用的核心部分。Cobra
提供了多种方式来接收和处理参数,包括标志(flags
)和位置参数(arguments
)。
flags 参数
标志是用于提供额外信息的参数,通常以 --flag=value 或 -f value 形式出现。Cobra 支持全局标志和本地标志,标志可以是布尔型、整数型、浮点型或字符串型。
我们可以在原来的程序中,创建 funCmd
之后添加这么一段代码:
// 添加命令行参数,并设置默认值,使用StringVarP方法,第一个参数是指针,第二个参数是命令行参数名称,第三个参数是命令行参数的简写,第四个参数是默认值,第五个参数是命令行参数的描述
funCmd.Flags().StringP("name", "n", "FunTester", "姓名,用于打印")
复制代码
然后我们在参数 Run
参数中这么处理:
Run: func(cmd *cobra.Command, args []string) {
name, err := cmd.Flags().GetString("name")
if err == nil {
fmt.Printf("Hello, %s ! \n", name)
} else {
fmt.Println(fmt.Sprintln(err))
}
},
复制代码
这样我们就可以接收参数了,使用方法如下:
╰─⠠⠵ ./funtester --name FunTester001
Hello, FunTester001 !
╰─⠠⠵ ./funtester -n FunTester002
Hello, FunTester002 !
复制代码
同样地,Cobra
还提供了整型和浮点型数据接收和获取方法,这里就不一一展示了。完整代码如下:
package main
import (
"fmt"
"github.com/spf13/cobra" "log")
func main() {
funCmd := &cobra.Command{
Use: "fun",
Short: "Demo of Cobra,打印 FunTester !!!",
Long: "Demo of Cobra,打印 FunTester !!!,使用Cobra构建命令行工具,实现简单的命令行功能",
Run: func(cmd *cobra.Command, args []string) {
name, err := cmd.Flags().GetString("name")
if err == nil {
fmt.Printf("Hello, %s age: %s ! \n", name, age)
} else {
fmt.Println(fmt.Sprintln(err))
}
},
}
// 添加命令行参数,并设置默认值,使用StringVarP方法,第一个参数是指针,第二个参数是命令行参数名称,第三个参数是命令行参数的简写,第四个参数是默认值,第五个参数是命令行参数的描述
funCmd.Flags().StringP("name", "n", "FunTester", "姓名,用于打印")
if err := funCmd.Execute(); err != nil {
log.Fatal(err)
}
}
复制代码
如果我们想直接使用当前的属性或者对象接收参数值,我们可以用下面的方法:
package main
import (
"fmt"
"github.com/spf13/cobra" "log")
func main() {
var name string
funCmd := &cobra.Command{
Use: "fun",
Short: "Demo of Cobra,打印 FunTester !!!",
Long: "Demo of Cobra,打印 FunTester !!!,使用Cobra构建命令行工具,实现简单的命令行功能",
Args: cobra.ExactArgs(1), // 限制参数个数,只能有一个参数,否则报错
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Hello, %s ! \n", name)
},
}
// 添加命令行参数,并设置默认值,和提示信息,以及参数的简写,和参数的使用说明
funCmd.Flags().StringVarP(&name, "name", "n", "FunTester", "姓名,用于打印")
if err := funCmd.Execute(); err != nil {
log.Fatal(err)
}
}
复制代码
如果我们定义一些必传参数,可以用下面的语法:
funCmd.MarkFlagRequired("name")
位置参数
位置参数是命令行中紧跟在命令后面的参数,它们不以 --flag 的形式出现。位置参数可以是必需的,也可以是可选的。
我们在上一版代码的基础上添加新的代码,增加了 Args
参数控制位置参数的个数,然后在 Run
参数中处理位置参数。完整代码如下:
package main
import (
"fmt"
"github.com/spf13/cobra" "log")
func main() {
funCmd := &cobra.Command{
Use: "fun",
Short: "Demo of Cobra,打印 FunTester !!!",
Long: "Demo of Cobra,打印 FunTester !!!,使用Cobra构建命令行工具,实现简单的命令行功能",
Args: cobra.ExactArgs(1), // 限制参数个数,只能有一个参数,否则报错
Run: func(cmd *cobra.Command, args []string) {
age := args[0]
name, err := cmd.Flags().GetString("name")
if err == nil {
fmt.Printf("Hello, %s age: %s ! \n", name, age)
} else {
fmt.Println(fmt.Sprintln(err))
}
},
}
// 添加命令行参数,并设置默认值,使用StringVarP方法,第一个参数是指针,第二个参数是命令行参数名称,第三个参数是命令行参数的简写,第四个参数是默认值,第五个参数是命令行参数的描述
funCmd.Flags().StringP("name", "n", "FunTester", "姓名,用于打印")
if err := funCmd.Execute(); err != nil {
log.Fatal(err)
}
}
复制代码
下面我们来编译执行看看。
╰─⠠⠵ ./funtester 123 --name FunTester002
Hello, FunTester002 age: 123 !
╰─⠠⠵ ./funtester --name FunTester002 3242
Hello, FunTester002 age: 3242 !
╰─⠠⠵ ./funtester --name FunTester002
Error: accepts 1 arg(s), received 0
Usage:
fun [flags]
Flags:
-h, --help help for fun
-n, --name string 姓名,用于打印 (default "FunTester")
2024/07/26 15:21:23 accepts 1 arg(s), received 0
复制代码
可以看出,位置参数无论在前还是在后,都不影响,但是如果缺少,就会报错。不得不说,Cobra
兼容性还不错。
如果我们位置参数数量不固定,对于参数的要求也比较多,可以参考 cobra.PositionalArgs
来解决,这里定义:
type PositionalArgs func(cmd *Command, args []string) error
下面是 Cobra
提供的几种实现类型:
在 Cobra 中,PositionalArgs
是一个用于定义和验证命令行位置参数的类型。它允许你指定命令的参数数量和验证规则。以下是几种常见的 PositionalArgs
验证函数以及如何使用它们的示例:
常见的 PositionalArgs
验证函数
cobra.NoArgs
:不接受任何位置参数。
cobra.ArbitraryArgs
:接受任意数量的位置参数。
cobra.ExactArgs(n int)
:接受确切数量的参数。
cobra.MinimumNArgs(n int)
:接受至少 n 个参数。
cobra.MaximumNArgs(n int)
:接受最多 n 个参数.
cobra.RangeArgs(min, max int)
:接受参数数量在指定范围内(包括边界)。
示例代码
以下是一些使用 PositionalArgs
验证函数的示例:
cobra.NoArgs
: 不接受任何位置参数。
cobra.ArbitraryArgs
: 接受任意数量的位置参数。
cobra.ExactArgs(n int)
: 接受确切数量的参数。
cobra.MinimumNArgs(n int)
: 接受至少 n 个参数。
cobra.MaximumNArgs(n int)
: 接受最多 n 个参数。
cobra.RangeArgs(min, max int)
: 接受参数数量在指定范围内。
这些验证函数使得处理和验证命令行参数变得更加简单和直观。根据应用的需求选择合适的 PositionalArgs
函数,可以确保用户提供正确数量和类型的参数,从而提高应用的可靠性和用户体验。
全局共享标志
在 Cobra
中,PersistentFlags
是用于在所有命令(包括子命令)中共享的标志。PersistentFlags
通常用于定义全局设置或配置参数,这些参数在所有命令中都可以使用。
使用方法如下:
// 为命令添加参数,默认值为FunTester
funCmd.PersistentFlags().StringP("name", "n", "FunTester", "姓名,用于打印")
复制代码
这个方法通常在构建子命令的时候用到,在父命令添加标志,所有的子命令也同时会拥有同样的标识。
子命令
在 Cobra 中,子命令(Subcommands)是命令行工具的一部分,使得工具能够包含多个操作或功能,每个子命令都可以有自己的标志和参数。子命令让命令行工具更加模块化和灵活。
下面是一个简单的例子:
package main
import (
"fmt"
"github.com/spf13/cobra" "log")
func main() {
var name string
funCmd := &cobra.Command{
Use: "fun",
Short: "Demo of Cobra,打印 FunTester !!!",
Long: "Demo of Cobra,打印 FunTester !!!,使用Cobra构建命令行工具,实现简单的命令行功能",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Hello, %s ! \n", name)
},
}
// 为命令添加参数,默认值为FunTester
funCmd.PersistentFlags().StringVarP(&name, "name", "n", "FunTester", "姓名,用于打印")
funCmd.MarkFlagRequired("name") // 标记为必须参数
sub := &cobra.Command{
Use: "sub",
Short: "sub command",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("sub command print: " + name)
},
}
funCmd.AddCommand(sub)
if err := funCmd.Execute(); err != nil {
log.Fatal(err)
}
}
复制代码
使用方法如下:
╰─⠠⠵ ./funtester sub --name FunTester002 32432
sub command print: FunTester002
复制代码
其他
Cobra
其他一些高级功能,暂时还用不到,有兴趣的可以自行研究研究。PS:要生成 Markdown 文档并将其转换为 man 页面格式,可以使用 github.com/cpuguy83/go-md2man/v2/md2man
包。也可以使用 --help
来获取自动生成的提示信息。
评论