Go 语言命令行框架 Cobra

警告
本文最后更新于 2025-05-09,文中内容可能已过时。
内容简介
Cobra 是一个用于 Go 的 CLI 框架。它包含一个用于创建功能强大的现代 CLI 应用程序的库,以及一个用于快速生成基于 Cobra 的应用程序和命令文件的工具。

基本概念

Cobra 建立在命令、参数和标志这三个结构之上。要使用 Cobra 编写一个命令行程序,需要明确这三个概念。

  • 命令(COMMAND):命令代表应用程序要执行的具体动作或行为。它是 Cobra 的核心结构,决定了程序的逻辑分支。
  • 参数(ARG):参数是传递给命令的位置参数(Positional Arguments)。它们通常位于命令和标志之后,代表命令作用的具体对象(如文件名、URL、ID 等)。
  • 标志(FLAG):标志是用于修改命令行为的选项。它们类似于函数的命名参数,允许用户自定义命令的执行细节(如开启详细模式、指定端口、设置超时时间等)。

我们可以用一个经典的公式来概括它们的关系:APPNAME COMMAND ARGUMENTS --FLAGS

例如在git commit -m "fix bug" main.go中:

  • git 是应用名
  • commit 是 命令 (Command)
  • -m “fix bug” 是 标志 (Flags)
  • main.go 是 参数 (Arguments)
特性 命令 (Commands) 参数 (Arguments) 标志 (Flags)
含义 动作 (Verb) 对象 (Noun) 选项/修饰 (Adjective/Option)
位置 紧跟应用名或父命令后 通常在命令后,标志前后均可 通常在命令后,以 --- 开头
示例 build, run, test main.go, user_id, url --output, -v, --force
Cobra 属性 *cobra.Command args []string cmd.Flags(), cmd.PersistentFlags()
验证方式 通过 Run 函数逻辑 通过 Args 验证器 (如 ExactArgs) 通过类型绑定和 Validate 函数
层级性 支持无限嵌套子命令 属于当前命令 分为本地标志和持久化标志

示例代码

cobra官方示例:在下面的示例中,我们定义了三个命令。两个在顶层,一个 (cmdTimes) 是其中一个顶层命令的子命令。在这种情况下,根目录不可执行,这意味着需要一个子命令。这是通过不为 ‘rootCmd’ 提供 ‘Run’ 来实现的。我们只为单个命令定义了一个标志。

 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package main

import (
  "fmt"
  "strings"

  "github.com/spf13/cobra"
)

func main() {
  var echoTimes int

  var cmdPrint = &cobra.Command{
    Use:   "print [string to print]",
    Short: "Print anything to the screen",
    Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("Print: " + strings.Join(args, " "))
    },
  }

  var cmdEcho = &cobra.Command{
    Use:   "echo [string to echo]",
    Short: "Echo anything to the screen",
    Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
      fmt.Println("Print: " + strings.Join(args, " "))
    },
  }

  var cmdTimes = &cobra.Command{
    Use:   "times [# times] [string to echo]",
    Short: "Echo anything to the screen more times",
    Long: `echo things multiple times back to the user by providing
a count and a string.`,
    Args: cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
      for i := 0; i < echoTimes; i++ {
        fmt.Println("Echo: " + strings.Join(args, " "))
      }
    },
  }

  cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")

  var rootCmd = &cobra.Command{Use: "app"}
  rootCmd.AddCommand(cmdPrint, cmdEcho)
  cmdEcho.AddCommand(cmdTimes)
  rootCmd.Execute()
}

最佳实践

Cobra 的根命令(Root Command)默认就是可执行的。如果没有其他子命令,仅定义了一个rootcommand,在rootcommand下定义了flags,同时在go build应用时,应用名和rootcommand取名一样,那么可以直接使用应用加flags启动服务。

实践中根命令名称与二进制名称可以不同,或者根命令仅作为入口。很多 CLI 工具(如 git, kubectl)的根命令通常不执行具体业务逻辑,只打印帮助信息,或者作为全局标志的容器。例如:

 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
27
28
29
30
31
32
33
[root@iZbp18sfxy8ixd9t5vscnaZ ~]# git
usage: git [--version] [--help] [-c name=value]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

The most commonly used git commands are:
   add        Add file contents to the index
   bisect     Find by binary search the change that introduced a bug
   branch     List, create, or delete branches
   checkout   Checkout a branch or paths to the working tree
   clone      Clone a repository into a new directory
   commit     Record changes to the repository
   diff       Show changes between commits, commit and working tree, etc
   fetch      Download objects and refs from another repository
   grep       Print lines matching a pattern
   init       Create an empty Git repository or reinitialize an existing one
   log        Show commit logs
   merge      Join two or more development histories together
   mv         Move or rename a file, a directory, or a symlink
   pull       Fetch from and merge with another repository or a local branch
   push       Update remote refs along with associated objects
   rebase     Forward-port local commits to the updated upstream head
   reset      Reset current HEAD to the specified state
   rm         Remove files from the working tree and from the index
   show       Show various types of objects
   status     Show the working tree status
   tag        Create, list, delete or verify a tag object signed with GPG

'git help -a' and 'git help -g' lists available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.

ceshi

Buy me a coffee
beneliu 支付宝支付宝
beneliu 微信微信