Cobra 是一个 Go 语言开发的命令行(CLI)框架,它提供了简洁、灵活且强大的方式来创建命令行程序。它包含一个用于创建命令行程序的库(Cobra 库),以及一个用于快速生成基于 Cobra 库的命令行程序工具(Cobra 命令)。Cobra 是由 Go 团队成员 spf13 为 Hugo 项目创建的,并已被许多流行的 Go 项目所采用,如 Kubernetes、Helm、Docker (distribution)、Etcd 等。
var rootCmd = &cobra.Command{ Use: "hugo", Short: "Hugo is a very fast static site generator", Long: `A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at https://gohugo.io`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("run hugo...") }, }
按照编写 Go 程序的惯例,我们要为 hugo 程序编写一个 main.go 文件,作为程序的启动入口。
hugo/main.go
1 2 3 4 5 6 7 8 9
package main
import ( "hugo/cmd" )
funcmain() { cmd.Execute() }
main.go 代码实现非常简单,只在 main 函数中调用了 cmd.Execute() 函数,来执行命令。
编译并运行命令
现在,我们就可以编译并运行这个命令行程序了。
1 2 3 4 5
# 编译 $ go build -o hugo # 执行 $ ./hugo run hugo...
笔记:示例代码里没有打印 Run 函数的 args 参数内容,你可以自行打印看看结果(提示:args 为命令行参数列表)。
以上我们编译并执行了 hugo 程序,输出内容正是 cobra.Command 结构体中 Run 函数内部代码的执行结果。
我们还可以使用 --help 查看这个命令行程序的使用帮助。
1 2 3 4 5 6 7 8 9 10
$ ./hugo --help A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at https://gohugo.io
Usage: hugo [flags]
Flags: -h, --helphelpfor hugo
这里打印了 cobra.Command 结构体中 Long 属性的内容,如果 Long 属性不存在,则打印 Short 属性内容。
hugo 命令用法为 hugo [flags],如 hugo --help。
这个命令行程序自动支持了 -h/--help 标志。
以上就是使用 Cobra 编写一个命令行程序最常见的套路,这也是 Cobra 推荐写法。
当前项目目录结构如下:
1 2 3 4 5 6 7
$ tree hugo hugo ├── cmd │ └── root.go ├── go.mod ├── go.sum └── main.go
var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version number of Hugo", Long: `All software has versions. This is Hugo's`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") }, }
funcinit() { rootCmd.AddCommand(versionCmd) }
现在重新编译并运行命令行程序。
1 2 3
$ go build -o hugo $ ./hugo version Hugo Static Site Generator v0.9 -- HEAD
可以发现 version 命令已经被加入进来了。
再次查看帮助信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$ ./hugo -h A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at https://gohugo.io
Usage: hugo [flags] hugo [command]
Available Commands: completion Generate the autocompletion script for the specified shell help Help about any command version Print the version number of Hugo
Flags: -h, --helphelpfor hugo
Use "hugo [command] --help"for more information about a command.
这次的帮助信息更为丰富,除了可以使用 hugo [flags] 语法,由于子命令的加入,又多了一个 hugo [command] 语法可以使用,如 hugo version。
$ go build -o hugo $ ./hugo -h A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at https://gohugo.io
Usage: hugo [flags] hugo [command]
Available Commands: completion Generate the autocompletion script for the specified shell help Help about any command print version Print the version number of Hugo
Flags: -h, --helphelpfor hugo -r, --region string AWS region (required) -s, --source string Source directory to read from -v, --verbose verbose output
Use "hugo [command] --help"for more information about a command.
# 编译 $ go build -o hugo # 两个命令参数满足验证函数的要求 $ ./hugo version a b Hugo Static Site Generator v0.9 -- HEAD # 超过两个参数则报错 $ ./hugo version a b c Error: accepts at most 2 arg(s), received 3
var printCmd = &cobra.Command{ Use: "print [OPTIONS] [COMMANDS]", Run: func(cmd *cobra.Command, args []string) { fmt.Println("run print...") // 命令行位置参数列表:例如执行 `hugo print a b c d` 将得到 [a b c d] fmt.Printf("args: %v\n", args) }, // 使用自定义验证函数 Args: func(cmd *cobra.Command, args []string)error { iflen(args) < 1 { return errors.New("requires at least one arg") } iflen(args) > 4 { return errors.New("the number of args cannot exceed 4") } if args[0] != "a" { return errors.New("first argument must be 'a'") } returnnil }, }
重新编译并运行 hugo 命令:
1 2 3 4 5 6 7 8 9 10 11 12
# 编译 $ go build -o hugo # 4 个参数满足条件 $ ./hugo print a b c d run print... args: [a b c d] # 没有参数则报错 $ ./hugo print Error: requires at least one arg # 第一个参数不满足验证函数逻辑,也会报错 $ ./hugo print x Error: first argument must be 'a'
# 编译 $ go build -o hugo # 执行 $ ./hugo hugo PersistentPreRunE hugo PreRunE Error: PreRunE err Usage: hugo [flags] hugo [command]
Available Commands: completion Generate the autocompletion script for the specified shell help Help about any command print version Print the version number of Hugo
Flags: --author string Author name for copyright attribution (default "YOUR NAME") -c, --config string config file -h, --helphelpfor hugo -r, --region string AWS region (required) -s, --source string Source directory to read from -v, --verbose verbose output
Use "hugo [command] --help"for more information about a command.
# 编译 $ go build -o hugo # 执行子命令 $ ./hugo version version PersistentPreRun version PreRun Hugo Static Site Generator v0.9 -- HEAD hugo PersistentPostRun
默认情况下,我们可以使用 hugo help command 语法查看子命令的帮助信息,也可以使用 hugo command -h/--help 查看。
使用 help 命令查看帮助信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
$ ./hugo help version hugo PersistentPreRunE All software has versions. This is Hugo's Usage: hugo version [flags] Flags: -h, --help help for version Global Flags: --author string Author name for copyright attribution (default "YOUR NAME") -v, --verbose verbose output hugo PersistentPostRun
使用 -h/--help 查看帮助信息:
1 2 3 4 5 6 7 8 9 10 11 12
$ ./hugo version -h All software has versions. This is Hugo's Usage: hugo version [flags] Flags: -h, --help help for version Global Flags: --author string Author name for copyright attribution (default "YOUR NAME") -v, --verbose verbose output
二者唯一的区别是,使用 help 命令查看帮助信息时会执行钩子函数。
我们可以使用 rootCmd.SetHelpCommand 来控制 help 命令输出,使用 rootCmd.SetHelpFunc 来控制 -h/--help 输出。
# 编译 $ go build -o hugo # 查看帮助 $ ./hugo -h Custom Help Template: Usage: hugo [flags] Description: Hugo is a very fast static site generator Commands: completion: Generate the autocompletion script for the specified shell help: Help about any command print: version: Print the version number of Hugo # 查看子命令帮助 $ ./hugo help version hugo PersistentPreRunE Custom Help Template: Usage: hugo version [flags] Description: Print the version number of Hugo Commands: hugo PersistentPostRun
可以发现,无论使用 help 命令查看帮助信息,还是使用 -h 查看帮助信息,其输出内容都遵循我们自定义的模版格式。
$ ./hugo --demo Error: unknown flag: --demo Usage: hugo [flags] hugo [command]
Available Commands: completion Generate the autocompletion script for the specified shell help Help about any command print version Print the version number of Hugo
Flags: --author string Author name for copyright attribution (default "YOUR NAME") -c, --config string config file -h, --helphelpfor hugo -s, --source string Source directory to read from -v, --verbose verbose output
Use "hugo [command] --help"for more information about a command.
SuggestionsMinimumDistance 是一个正整数,表示输错的命令与正确的命令最多有几个不匹配的字符(最小距离),才会给出建议。如当值为 1 时,用户输入 hugo versiox 会给出建议,而如果用户输入 hugo versixx 时,则不会给出建议,因为已经有两个字母不匹配 version 了。
$ ./hugo completion Generate the autocompletion script for hugo for the specified shell. See each sub-command's help for details on how to use the generated script. Usage: hugo completion [command] Available Commands: bash Generate the autocompletion script for bash fish Generate the autocompletion script for fish powershell Generate the autocompletion script for powershell zsh Generate the autocompletion script for zsh Flags: -h, --help help for completion Global Flags: --author string Author name for copyright attribution (default "YOUR NAME") -v, --verbose verbose output Use "hugo completion [command] --help" for more information about a command.
如果要让命令行补全功能永久生效,Cobra 则非常贴心的为 Linux 和 macOS 提供了不同命令。
你可以根据提示选择自己喜欢的方式来实现命令行补全功能。
我这里只实现为当前会话提供命令行补全功能为例进行演示:
1 2 3 4 5 6 7 8 9 10 11
# 首先在项目根目录下,安装 hugo 命令行程序,安装后软件存放在 $GOPATH/bin 目录下 $ go install . # 添加命令行补全功能 $ source <(hugo completion zsh) # 现在命令行补全已经生效,只需要输入一个 `v`,然后按下键盘上的 `Tab` 键,命令将自动补全为 `version` $ hugo v # 命令已被自动补全 $ hugo version version PersistentPreRun version PreRun Hugo Static Site Generator v0.9 -- HEAD
$ cobra-cli -h Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.
Usage: cobra-cli [command]
Available Commands: add Add a command to a Cobra Application completion Generate the autocompletion script for the specified shell help Help about any command init Initialize a Cobra Application
Flags: -a, --author string author name for copyright attribution (default "YOUR NAME") --config string config file (default is $HOME/.cobra.yaml) -h, --helphelpfor cobra-cli -l, --license string name of license for the project --viper use Viper for configuration
Use "cobra-cli [command] --help"for more information about a command.
可以发现,cobra-cli 脚手架工具仅提供了少量命令和标志,所以上手难度不大。
初始化模块
要使用 cobra-cli 生成一个项目,首先要手动创建项目根目录并使用 go mod 命令进行初始化。
假设我们要编写的命令行程序叫作 cog,模块初始化过程如下:
1 2 3 4 5 6
# 创建项目目录 $ mkdir cog # 进入项目目录 $ cd cog # 初始化模块 $ go mod init github.com/jianghushinian/blog-go-example/cobra/getting-started/cog
# 初始化程序 $ cobra-cli init Your Cobra application is ready at # 查看生成的项目目录结构 $ tree . . ├── LICENSE ├── cmd │ └── root.go ├── go.mod ├── go.sum └── main.go
2 directories, 5 files # 执行命令行程序 $ go run main.go A longer description that spans multiple lines and likely contains examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.
使用 cobra-cli 初始化程序非常方便,只需要一个简单的 init 命令即可完成。
目录结构跟我们手动编写的程序相同,只不过多了一个 LICENSE 文件,用来存放项目的开源许可证。
通过 go run main.go 执行这个命令行程序,即可打印 rootCmd.Run 的输出结果。
// rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "cog", Short: "A brief description of your application", Long: `A longer description that spans multiple lines and likely contains examples and usage of using your application. For example: Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application.`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, }
// Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. funcExecute() { err := rootCmd.Execute() if err != nil { os.Exit(1) } }
funcinit() { // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application.
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cog.yaml)")
// Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") }