• 基于cobra的go语言命令行解析器


    ubuntu安装cobra

    $ sudo apt install cobra
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    The following NEW packages will be installed:
      cobra
    0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
    Need to get 2,873 kB of archives.
    After this operation, 9,495 kB of additional disk space will be used.
    Get:1 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal/universe amd64 cobra amd64 0.0.5-1 [2,873 kB]
    Fetched 2,873 kB in 2s (1,272 kB/s) 
    Selecting previously unselected package cobra.
    (Reading database ... 188150 files and directories currently installed.)
    Preparing to unpack .../cobra_0.0.5-1_amd64.deb ...
    Unpacking cobra (0.0.5-1) ...
    Setting up cobra (0.0.5-1) ...
    Processing triggers for man-db (2.9.1-1) ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Go在项目中使用cobra

    import "github.com/spf13/cobra/cobra"
    
    • 1

    使用cobra创建项目
    创建项目建议使用Go module模式,首先,创建一个go module项目,项目名称为arsenal

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# go mod init arsenal
    go: creating new go.mod: module arsenal
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ll
    total 12
    drwxr-xr-x 2 root root 4096 1118 21:25 ./
    drwxr-xr-x 6  644 root 4096 1118 21:25 ../
    -rw-r--r-- 1 root root   24 1118 21:25 go.mod
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    arsenal目录中添加cobra项目。

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# cobra init --pkg-name arsenal
    Your Cobra applicaton is ready at
    /home/curtis/go_env/arsenal
    
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# tree .
    .
    ├── cmd
    │   └── root.go	# 最顶层的命令rootCmd
    ├── go.mod
    ├── LICENSE	 # license信息
    └── main.go
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    编译之前下载几个依赖包

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# go build
    cmd/root.go:24:3: no required module provides package github.com/mitchellh/go-homedir; to add it:
    	go get github.com/mitchellh/go-homedir
    cmd/root.go:22:3: no required module provides package github.com/spf13/cobra; to add it:
    	go get github.com/spf13/cobra
    cmd/root.go:25:3: no required module provides package github.com/spf13/viper; to add it:
    	go get github.com/spf13/viper
    
    # 执行生成的可执行文件
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal 
    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.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    编译出来的二进制文件arsenal默认打印的信息是怎么来的?来自rootCmd命令的长描述信息。

    // cmd/root.go
    // rootCmd represents the base command when called without any subcommands
    var rootCmd = &cobra.Command{
      Use:   "arsenal",
      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) { },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    尝试修改rootCmd命令的描述信息。

    var rootCmd = &cobra.Command{
            Use:   "arsenal",
            Short: "A brief description of your application",
            Long: "This is long description of your application",	// 出现在-h的帮助信息中
            // Uncomment the following line if your bare application
            // has an action associated with it:
            //      Run: func(cmd *cobra.Command, args []string) { },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    执行命令

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal 
    This is long description of your application
    
    • 1
    • 2

    添加子命令,比如说添加一个版本信息

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# cobra add version
    version created at /home/curtis/go_env/arsenal
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# tree .
    .
    ├── arsenal
    ├── cmd
    │   ├── root.go
    │   └── version.go	# 新添加了一个versoin.go
    ├── go.mod
    ├── go.sum
    ├── LICENSE
    └── main.go
    
    # go build编译之后执行命令
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal 
    This is long description of your application
    
    Usage:
      arsenal [command]
    
    Available Commands:
      completion  Generate the autocompletion script for the specified shell
      help        Help about any command	# 添加的子命令
      version     This short information about version	# 可以看到version子命令的短描述信息
    
    Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
      -h, --help            help for arsenal
      -t, --toggle          Help message for toggle
    
    Use "arsenal [command] --help" for more information about a command.
    
    # 执行了注册的Run 函数,该函数打印了信息version called
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal version 
    version called
    
    # -h 信息可以看到version 命令的长信息
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal version -h
    This long information about version
    
    Usage:
      arsenal version [flags]
    
    Flags:
      -h, --help   help for version
    
    Global Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
    
    • 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

    如何把命令绑定到父命令中,可以无限制的往下添加,但是需要注意的是每个cobra.command结构体只能指向一个parent cobra.command

    # 不做任何处理
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# cobra add cpu
    cpu created at /home/curtis/go_env/arsenalroot@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# 
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# tree .
    .
    ├── arsenal
    ├── cmd
    │   ├── cpu.go
    │   ├── root.go
    │   └── version.go
    ├── go.mod
    ├── go.sum
    ├── LICENSE
    └── main.go
    
    1 directory, 8 files
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# go build
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal 
    This is long description of your application
    
    Usage:
      arsenal [command]
    
    Available Commands:
      completion  Generate the autocompletion script for the specified shell
      cpu         A brief description of your command
      help        Help about any command
      version     This short information about version
    
    Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
      -h, --help            help for arsenal
      -t, --toggle          Help message for toggle
    
    Use "arsenal [command] --help" for more information about a command.
    
    • 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

    添加子命令
    将上述cpu子命令添加到version下修改之后。

    // 只需要将cpuCmd添加到versionCmd之下就可以了。
    func init() {
    	// 使用cobra add默认将命令添加到rootCmd
    	// 可以尝试修改添加到version cmd之下
    	versionCmd.AddCommand(cpuCmd)
    
    	// Here you will define your flags and configuration settings.
    
    	// Cobra supports Persistent Flags which will work for this command
    	// and all subcommands, e.g.:
    	// cpuCmd.PersistentFlags().String("foo", "", "A help for foo")
    
    	// Cobra supports local flags which will only run when this command
    	// is called directly, e.g.:
    	// cpuCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal version -h
    This long information about version
    
    Usage:
      arsenal version [flags]
      arsenal version [command]
    
    Available Commands:
      cpu         A brief description of your command	# 子命令添加成功
    
    Flags:
      -h, --help   help for version
    
    Global Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
    
    Use "arsenal version [command] --help" for more information about a command.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    选项的接收与处理

    var versionCmd = &cobra.Command{
    	Use:   "version",
    	Short: "This short information about version",
    	Long:  "This long information about version",
    
    	Run: func(cmd *cobra.Command, args []string) {
    		fmt.Println("version called")
    		// 各个选项参数获取
    		auther, err := cmd.Flags().GetString("auther")
    		if err != nil {
    			fmt.Println("请输入正确的作者信息")
    			return
    		}
    
    		fmt.Println("作者是: ", auther)
    	},
    }
    
    func init() {
    	rootCmd.AddCommand(versionCmd)
    
    	// Here you will define your flags and configuration settings.
    
    	// Cobra supports Persistent Flags which will work for this command
    	// and all subcommands, e.g.:
    	// versionCmd.PersistentFlags().String("foo", "", "A help for foo")
    
    	// Cobra supports local flags which will only run when this command
    	// is called directly, e.g.:
    	// versionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
    	// 添加version参数auther,a为别名,默认值为cutis
    	versionCmd.Flags().StringP("auther", "a", "curtis", "The auther name")
    	// 添加version参数percent,p为别名,默认值为60%
    	versionCmd.Flags().StringP("percent", "p", "60%", "The percent of cpu")
    }
    
    • 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
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal version -h
    This long information about version
    
    Usage:
      arsenal version [flags]
      arsenal version [command]
    
    Available Commands:
      cpu         A brief description of your command
    
    Flags:
      -a, --auther string    The auther name (default "curtis")
      -h, --help             help for version
      -p, --percent string   The percent of cpu (default "60%")
    
    Global Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
    
    Use "arsenal version [command] --help" for more information about a command.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    选项常见的类型

    • 布尔值
    • 数字(各种整形,浮点数等)
    • 字符串
    • 其他高级类型

    选项的帮助信息

    命令自动补全补全功能
    从上面构建的工程来看,cobra已经把自动补全的功能默认添加到项目中,使用方法如下所示。

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal completion bash -h 
    Generate the autocompletion script for the bash shell.
    
    This script depends on the 'bash-completion' package.
    If it is not installed already, you can install it via your OS's package manager.
    
    To load completions in your current shell session:
    
    	source <(arsenal completion bash)	# 只有在当前shell终端生效
    
    To load completions for every new session, execute once:
    
    #### Linux:
    
    	arsenal completion bash > /etc/bash_completion.d/arsenal	# 永久生效
    
    #### macOS:
    
    	arsenal completion bash > $(brew --prefix)/etc/bash_completion.d/arsenal
    
    # 需要重新开启新的终端才会生效
    You will need to start a new shell for this setup to take effect.
    
    Usage:
      arsenal completion bash
    
    Flags:
      -h, --help              help for bash
          --no-descriptions   disable completion descriptions
    
    Global Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
    
    • 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

    启用自动补全功能之后,使用tab命令没有自动补全,报错如下。

    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# source <(./arsenal completion bash)
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal ver_get_comp_words_by_ref: command not found
    _get_comp_words_by_ref: command not found
    _get_comp_words_by_ref: command not found
    
    • 1
    • 2
    • 3
    • 4

    可能原因是有可能没有安装bash-completion包,安装方法即开启命令自动补全如下所示。

    # 安装bash-completion包
    $ sudo apt install bash-completion
    
    # 启用completion功能
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# source /usr/share/bash-completion/bash_completion
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# source <(./arsenal completion bash)
    
    # 可以使用tab键自动补全命令
    root@curtis-Aspire-E5-471G:/home/curtis/go_env/arsenal# ./arsenal version cpu
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    自定义配置文件中读取cli命令行相关参数
    常见的配置文件类型有json,yaml从上述注册的命令来看,还有一个可选项,那就是从配置文件中读取cli命令行相关参数。用cobra命令初始化的模块默认的文件格式为yaml。

    Global Flags:
          --config string   config file (default is $HOME/.arsenal.yaml)
    
    • 1
    • 2

    获取命令行中的所有flags

    // 返回指向Flag结构体的指针f
    func checkFlags(f *pflag.Flag) {
    	fmt.Println(f.Name)
    }
    
    // 访问命令行中已经输入的flags
    func main(){
      flagset.Visit(checkFlags);
    }
    
    // 访问所有定义的flags
    func main(){
      flagset.VisitAll(checkFlags);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    示例代码:

    func checkFlags(f *pflag.Flag) {
    	fmt.Println(f.Name)
    }
    
    // cpuCmd represents the cpu command
    var cpuCmd = &cobra.Command{
    	Use:   "cpu",
    	Short: "A brief description of your command",
    	Long: `A longer description that spans multiple lines and likely contains examples
    and usage of using your command. 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.`,
    	Run: func(cmd *cobra.Command, args []string) {
    		fmt.Println("cpu called")
    
    		// flags := cmd.Flags()
    		// fmt.Println(flags)
    
    		cmd.Flags().Visit(checkFlags)
    	},
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    成功解析当前命令行输入的所有flags,想要获取flags所对应的值,cmd.Flags()下有对应的方法。

    curtis@curtis-Aspire-E5-471G:~/go_env/arsenal$ ./arsenal version cpu -p ./ll -a curtis
    cpu called
    author
    file-name
    
    • 1
    • 2
    • 3
    • 4

    获取某个command的帮助信息

    func getUsageInfo(cmd *cobra.command, args []string) {
    	usageInfo := cmd.Flags().FlagUsages()
    	fmt.Println(usageInfo)
    }
    
    • 1
    • 2
    • 3
    • 4

    获取Flagset的所有信息

    flagInfo := cmd.Flags()
    fmt.Println(flagInfo )
    
    • 1
    • 2

    代码实例

    // cpuCmd represents the cpu command
    var cpuCmd = &cobra.Command{
    	Use:   "cpu",
    	Short: "A brief description of your command",
    	Long: `A longer description that spans multiple lines and likely contains examples
    and usage of using your command. 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.`,
    	Run: func(cmd *cobra.Command, args []string) {
    		fmt.Println("cpu called")
    
    		flags := cmd.Flags()
    		fmt.Println(flags)
    	},
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    打印信息如下,为结构体FlagSet所对应的详细信息。

    &{<nil> true {false} cpu true map[author:0xc0000bbae0 file-name:0xc0000bba40] [0xc0000bba40 0xc0000bbae0] [] map[author:0xc0000bbae0 config:0xc0000bbb80 file-name:0xc0000bba40 help:0xc0001380a0] [0xc0000bba40 0xc0000bbae0 0xc0000bbb80 0xc0001380a0] [0xc0000bbae0 0xc0000bbb80 0xc0000bba40 0xc0001380a0] map[97:0xc0000bbae0 104:0xc0001380a0 112:0xc0000bba40] [] -1 0 0xc00009b800 true <nil> []}
    
    • 1
  • 相关阅读:
    微信小程序 | 吐血整理的日历及日程时间管理
    【现代控制理论】| 线性系统的状态空间法
    JAVA 常见算法(选择排序,二分查找)
    【生成式AI】ChatGPT 原理解析(2/3)- 预训练 Pre-train
    springboot高校二手服饰交易系统服装商城idea mysql
    springboot实现简单的注册登录功能
    初级测试到中级测试就差这几个找bug小技巧
    VScode写C++读文件时遇到的问题
    shell去除空行的办法
    Redis单机版搭建
  • 原文地址:https://blog.csdn.net/qq_42931917/article/details/127929918