1 go get github.com/spf13/cobra/cobra
简介 cobra 是一个命令行程序库,可以用来编写命令行程序。同时,它也提供了一个脚手架, 用于生成基于 cobra 的应用程序框架。非常多知名的开源项目使用了 cobra 库构建命令行,如 Kubernetes 、Hugo 、etcd 等等。
特性 cobra 提供非常丰富的功能:
轻松支持子命令,如 app server
,app fetch
等;
完全兼容 POSIX 选项(包括短、长选项);
嵌套子命令;
全局、本地层级选项。可以在多处设置选项,按照一定的顺序取用;
使用脚手架轻松生成程序框架和命令。
首先需要明确 3 个基本概念:
命令(Command):就是需要执行的操作;
参数(Arg):命令的参数,即要操作的对象;
选项(Flag):命令选项可以调整命令的行为。
下面示例中,server
是一个(子)命令,--port
是选项:
下面示例中,clone
是一个(子)命令,URL
是参数,--bare
是选项:
quick start 实现一个简单的命令行程序 git,当然这不是真的 git,只是模拟其命令行。最终还是通过 os/exec
库调用外部程序执行真实的 git 命令,返回结果。 所以我们的系统上要安装 git,且 git 在可执行路径中。目前我们只添加一个子命令 version
。目录结构如下:
1 2 3 4 5 6 ▾ get-started/ ▾ cmd/ helper.go root.go version.go main.go
root.go
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package cmdimport ( "errors" "github.com/spf13/cobra" ) var rootCmd = &cobra.Command { Use: "git" , Short: "Git is a distributed version control system." , Long: `Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.` , Run: func (cmd *cobra.Command, args []string ) { Error(cmd, args, errors.New("unrecognized command" )) }, } func Execute () { rootCmd.Execute() }
version.go
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package cmdimport ( "fmt" "os" "github.com/spf13/cobra" ) var versionCmd = &cobra.Command { Use: "version" , Short: "version subcommand show git version info." , Run: func (cmd *cobra.Command, args []string ) { output, err := ExecuteCommand("git" , "version" , args...) if err != nil { Error(cmd, args, err) } fmt.Fprint(os.Stdout, output) }, } func init () { rootCmd.AddCommand(versionCmd) }
main.go
文件中只是调用命令入口:
1 2 3 4 5 6 7 8 9 package mainimport ( "github.com/darjun/go-daily-lib/cobra/get-started/cmd" ) func main () { cmd.Execute() }
为了编码方便,在 helpers.go
中封装了调用外部程序和错误处理函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package cmdimport ( "fmt" "os" "os/exec" "github.com/spf13/cobra" ) func ExecuteCommand (name string , subname string , args ...string ) (string , error) { args = append ([]string {subname}, args...) cmd := exec.Command(name, args...) bytes, err := cmd.CombinedOutput() return string (bytes), err } func Error (cmd *cobra.Command, args []string , err error) { fmt.Fprintf(os.Stderr, "execute %s args:%v error:%v\n" , cmd.Name(), args, err) os.Exit(1 ) }
每个 cobra 程序都有一个根命令,可以给它添加任意多个子命令。我们在 version.go
的 init
函数中将子命令添加到根命令中。
调用子命令:
1 2 ./main.exe version git version 2.19.1.windows.1
未识别的子命令:
1 2 3 $ ./main.exe clone Error: unknown command "clone" for "git" Run 'git --help' for usage.
使用 cobra 构建命令行时,程序的目录结构一般比较简单,推荐使用下面这种结构:
1 2 3 4 5 6 7 ▾ appName/ ▾ cmd/ cmd1.go cmd2.go cmd3.go root.go main.go
每个命令实现一个文件,所有命令文件存放在 cmd
目录下。外层的 main.go
仅初始化 cobra。