写点什么

Cobra 库上手—自建命令行工具

作者:FunTester
  • 2024-08-08
    河北
  • 本文字数:5041 字

    阅读完需:约 17 分钟

Cobra 简介

Cobra 是一个流行的 Go 语言库,用于创建强大且灵活的命令行应用程序。它由 spf13 开发,设计用于与 Go 生态系统中的其他流行库(如 Viper 配置库)无缝集成。Cobra 支持多级命令结构,允许定义根命令和任意数量的子命令,还可以轻松处理全局和本地标志。它自动生成帮助和使用信息,并支持 BashZshFishPowerShell 的命令补全。此外,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 ,控制台就会打印


Hello, 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 FunTester001Hello, FunTester001 ! ╰─⠠⠵ ./funtester -n FunTester002Hello, 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 FunTester002Hello, FunTester002 age: 123 ! ╰─⠠⠵ ./funtester  --name FunTester002 3242Hello, FunTester002 age: 3242 ! ╰─⠠⠵ ./funtester --name FunTester002    Error: accepts 1 arg(s), received 0Usage:  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 验证函数

  1. cobra.NoArgs:不接受任何位置参数。

  2. cobra.ArbitraryArgs:接受任意数量的位置参数。

  3. cobra.ExactArgs(n int):接受确切数量的参数。

  4. cobra.MinimumNArgs(n int):接受至少 n 个参数。

  5. cobra.MaximumNArgs(n int):接受最多 n 个参数.

  6. 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 32432sub command print: FunTester002
复制代码

其他

Cobra 其他一些高级功能,暂时还用不到,有兴趣的可以自行研究研究。PS:要生成 Markdown 文档并将其转换为 man 页面格式,可以使用 github.com/cpuguy83/go-md2man/v2/md2man 包。也可以使用 --help 来获取自动生成的提示信息。

发布于: 刚刚阅读数: 4
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
Cobra 库上手—自建命令行工具_FunTester_InfoQ写作社区