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 <EMAIL ADDRESS>
*/
package cmdimport ("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")
}
开始使用spf13/cobra框架自行编写命令行工具
一个简单的开始
package mainimport ("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())}
}
自行控制参数解析,你也可以不用cobra框架,单纯用参数工具pflag(cobra依赖pflag解析参数,你如果依赖了cobra,就不用再go get github.com/spf13/pflag)
package mainimport ("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.FlagSetSilenceUsage: 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())}
}
参数解析设置别名
我觉得这是pflag最哇塞的一个功能
func setalias(f *pflag.FlagSet) {
//将所有参数名带-的,使用.也是一样的识别,这里name是参数原始名,返回的是别名。f.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {return pflag.NormalizedName(strings.ReplaceAll(name, "-", "."))})
}
最终演示代码
package mainimport ("demo/options""fmt""log""net""strings""time""github.com/spf13/cobra""github.com/spf13/pflag"
)var (flag_result struct {_type stringttl time.Durationip 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())}
}