• go 命令行框架cobra


    go 命令行框架cobra

    go 拉取依赖包go get github.com/spf13/cobra

    认识spf13/cobra-cli. cobra 命令行框架在golang中的地位也算得上是大明星级别。像k8s,docker都有使用这个框架构建自己命令行这块的功能.

    最最最简单的开始----使用命令行工具cobra-cli来初始化你的demo

    cobra-cli init 初始化你的demo.后面可以加目录名,不加就是当前目录下创建一个main.go 和cmd目录(如果这时你main.go里写了东西,先备份再初始化)。cmd目录cobra-cli是用来储存子命令的地方,后面我们手动写的时候这个就不重要了

    cobra-cli add options 添加一个子命令。例如你的demo名叫demo,你需要实现一个demo put xxxx的功能。cobra-cli add put

    cobra-cli add options -p parent_optionCmd 子命令添加子命令。例如给上面的put加一个子命令为single cobra-cli add single -p putCmd 这里p参数为指定该命令的父命令,需要加后缀Cmd,因为-p参数实际是代码中的参数名,而cobra-cli自动创建命令时参数名为格式为xxxxCmd

    编译demo. 运行demo 带-h查看cobra-cli生成的效果

    认识cobra-cli框架下的命令行命令构造

    每一个命令可以说是独立的,但是整个程序得有一个根命令rootCmd,这个rootCmd和其它命令性质都是一样的(都可以具备独立的flagset,usage)。只不过它的位置是“树根”而已
    请添加图片描述

    参数

    • 兼容golang 标准库flag.FlagSet
    • 能够设置必备参数(必填的参数)
    //以putCmd为例
    /*
    Copyright © 2024 NAME HERE 
    */
    package cmd
    
    import (
    	"fmt"
    	"log"
    
    	"github.com/spf13/cobra"
    )
    
    // putCmd represents the put command
    var putCmd = &cobra.Command{
    	Use:   "put",//子命令的具体名字
    	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("put called")
    	},
    }
    
    func init() {
    	rootCmd.AddCommand(putCmd)//将putCmd添加到rootCmd的分支上去。成为rootCmd的子命令
    	//为put命令添加参数,结尾有P的为带缩写的参数。添加的时候看清楚你添加的命令是哪一个,别搞混了搞到rootCmd上去了
    	fs := flag.NewFlagSet("put", flag.ExitOnError)
    	putCmd.Flags().AddGoFlagSet(fs)//添加go标准库中的flagset至put命令中
    	putCmd.Flags().String("type", "", "input type")
    	err := putCmd.MarkFlagRequired("type")//为这项命令添加必备参数。
    	if err != nil {
    		log.Fatalln(err)
    	}
    	// Here you will define your flags and configuration settings.
    
    	// Cobra supports Persistent Flags which will work for this command
    	// and all subcommands, e.g.:
    	// putCmd.PersistentFlags().String("foo", "", "A help for foo")
    
    	// Cobra supports local flags which will only run when this command
    	// is called directly, e.g.:
    	// putCmd.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
    • 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

    开始使用spf13/cobra框架自行编写命令行工具

    一个简单的开始

    package main
    
    import (
    	"fmt"
    	"log"
    
    	"github.com/spf13/cobra"
    )
    //你的子命令都可以通过这种方式创建,这么做可以操作的空间很多
    func NewCommand() *cobra.Command {
    	//这一块你可以做一些这个命令需要的变量初始化,rune函数里面就可以直接用了
    	var cmd = cobra.Command{
    		Use:                "demo",
    		Short:              "this is a simple sample",
    		RunE: func(cmd *cobra.Command, args []string) (err error) {//与rune 对应的还有run,两个都一样,只是返不返回错误的区别,我个人喜欢返回错误出去,最后统一处理。你可以根据自己喜好自行选者
    			fmt.Println("this is an example start")
    			return
    		},
    	}
    	//这里你可以做些命令行参数绑定什么的
    	return &cmd
    }
    
    func main() {
    	cmd := NewCommand()
    	err := cmd.Execute()
    	if err != nil {
    		log.Fatalln(err.Error())
    	}
    }
    
    
    • 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

    自行控制参数解析,你也可以不用cobra框架,单纯用参数工具pflag(cobra依赖pflag解析参数,你如果依赖了cobra,就不用再go get github.com/spf13/pflag)

    package main
    
    import (
    	"demo/options"
    	"log"
    	"time"
    
    	"github.com/spf13/cobra"
    	"github.com/spf13/pflag"
    )
    
    func getCommandFlags(f *pflag.FlagSet) {
    	f.String("type", "", "input type ")
    	f.Duration("ttl", time.Second, "ttl")
    }
    func NewCommand() *cobra.Command {
    	var cmd = cobra.Command{
    		Use:                "demo",
    		Short:              "this is a simple sample",
    		DisableFlagParsing: true,//使用我们自带的pflag.FlagSet
    		SilenceUsage:       true,//参数传入错误时不会把usage信息弹出来
    		RunE: func(cmd *cobra.Command, args []string) (err error) {
    			pf := pflag.NewFlagSet("demo", pflag.ContinueOnError)
    			getCommandFlags(pf)
    			cmd.Flags().AddFlagSet(pf)
    			help := pf.BoolP("help", "h", false, "--help")
    			err = pf.Parse(args)
    			if err == nil {
    				if *help {
    					return cmd.Help()
    				}
    			}
    			return
    		},
    	}
    	cmd.AddCommand(options.NewPutCommand())
    	return &cmd
    }
    
    func main() {
    	cmd := NewCommand()
    	err := cmd.Execute()
    	if err != nil {
    		log.Fatalln(err.Error())
    	}
    }
    
    • 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

    参数解析设置别名

    我觉得这是pflag最哇塞的一个功能

    func setalias(f *pflag.FlagSet) {
    //将所有参数名带-的,使用.也是一样的识别,这里name是参数原始名,返回的是别名。
    	f.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
    		return pflag.NormalizedName(strings.ReplaceAll(name, "-", "."))
    	})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    最终演示代码

    package main
    
    import (
    	"demo/options"
    	"fmt"
    	"log"
    	"net"
    	"strings"
    	"time"
    
    	"github.com/spf13/cobra"
    	"github.com/spf13/pflag"
    )
    
    var (
    	flag_result struct {
    		_type string
    		ttl   time.Duration
    		ip    net.IP
    	}
    )
    
    func getCommandFlags(f *pflag.FlagSet) {
    	f.StringVar(&flag_result._type, "type", "", "input type ")
    	f.DurationVar(&flag_result.ttl, "ttl", time.Second, "ttl")
    	f.IPVar(&flag_result.ip, "net-ip4", nil, "ip address")
    }
    func setalias(f *pflag.FlagSet) {
    	f.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
    		return pflag.NormalizedName(strings.ReplaceAll(name, "-", "."))
    	})
    }
    func NewCommand() *cobra.Command {
    	var cmd = cobra.Command{
    		Use:                "demo",
    		Short:              "this is a simple sample",
    		DisableFlagParsing: true,
    		SilenceUsage:       true,
    		RunE: func(cmd *cobra.Command, args []string) (err error) {
    			pf := pflag.NewFlagSet("demo", pflag.ContinueOnError)
    			getCommandFlags(pf)
    			setalias(pf)
    			cmd.Flags().AddFlagSet(pf)
    			help := pf.BoolP("help", "h", false, "--help")
    			err = pf.Parse(args)
    			if err == nil {
    				if *help {
    					return cmd.Help()
    				}
    				fmt.Println(flag_result._type, flag_result.ttl, flag_result.ip)
    			}
    			return
    		},
    	}
    	cmd.AddCommand(options.NewPutCommand())
    	return &cmd
    }
    
    func main() {
    	cmd := NewCommand()
    	err := cmd.Execute()
    	if err != nil {
    		log.Fatalln(err.Error())
    	}
    }
    
    
    • 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
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    请添加图片描述
    请添加图片描述
    请添加图片描述

  • 相关阅读:
    第四届传智杯初赛_小卡与质数2
    前 3 名突然变了?揭秘 7 月编程语言最新排行榜
    随机森林实战案例——对天气最高温度进行预测
    Tomcat报404问题的原因分析
    档案数字化管理能够带来哪些好处
    python 字符串类型
    计算机毕业设计 基于协同推荐的白酒销售管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
    【设计模式】策略模式
    IDEA撤回Git提交到本地仓库的代码
    TCP为什么需要三次握手和四次挥手?
  • 原文地址:https://blog.csdn.net/A_super_C/article/details/136429313