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 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")
}
开始使用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())
}
}
自行控制参数解析,你也可以不用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())
}
}
参数解析设置别名
我觉得这是pflag最哇塞的一个功能
func setalias(f *pflag.FlagSet) {
//将所有参数名带-的,使用.也是一样的识别,这里name是参数原始名,返回的是别名。
f.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
return pflag.NormalizedName(strings.ReplaceAll(name, "-", "."))
})
}
最终演示代码
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())
}
}