corba命令行解析工具,在看K8代码的时候发现有很多地方都用到了,这里说一下
项目地址
https://github.com/spf13/cobra
[appName] [command] [arguments] --[flag]
执行文件 动作 数值 参数
1、appName //执行文件本身,就是main.exe
1、commands //行为,具体操作的动作 比如K8的 get logs操作
2、arguments //表示数值
3、flags //表示对行为的改变
go get -u github.com/spf13/cobra/cobra
cobra init tools //初始化目录
vi main.go
package main
import "go_code/tools/cmd" //项目名称改成自己的
func main() {
cmd.Execute() //调用cmd下的函数载入命令行参数
}
vi root.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
)
//定义命令本身的变量
var rootCmd = &cobra.Command{
Use: "kubectl", //命令行工具的名称
Short: "短说明", //提示信息
Long: `长说明`, //提示信息2
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("hello world") //当使用这个命令时进行的操作
},
}
//触发函数
func Execute() {
err := rootCmd.Execute() //Execute使用args(默认情况下为os.args[1:])并在命令树中运行
// 为命令找到合适的匹配项,然后执行相应的命令
if err != nil {
os.Exit(1)
}
}
测试
D:\go_setup\go1.17\src\go_code\tools>go run main.go
hello world
我们在上面定义了一个命令体,他默认是没有设置参数的
如果我们直接输入参数,会提示我当前这个工具的名称以及帮助信息
D:\go_setup\go1.17\src\go_code\tools>go run main.go -t=true1
Error: unknown shorthand flag: 't' in -t=true1
Usage:
kubectl [flags]
Flags:
-h, --help help for kubectl
exit status 1
如果想要添加具体的命令行参数,需要这个主体命令上添加子命令
子命令是基于主体命令的子命令,也可以理解为一个子参数
添加子命令
cobra add get //会在cmd目录下新建一个name.go的模板文件
get.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var getCmd = &cobra.Command{
Use: "get",
Short: "我的短提示信息",
Long: `我是长提示信息`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("get called")
},
}
func init() {
rootCmd.AddCommand(getCmd) //注意这里rootCmd 表示当前这个命令是rootCmd的子命令
//它会继承rootcmd的所有操作方法,在主体命令下层
}
测试
可以看到,在主体命令下多了一个get的子命令
D:\go_setup\go1.17\src\go_code\tools>go run main.go get
get called
使用主体命令+子命令get,则会调用get子命令下的RUN程序
上面我们定义了动作(command) 要做什么,现在我们要定义一些特性
类似与Kubernetes 里面的-n -o -A 等选项操作
1、persistent //永久选项,它可以给子命令添加选项,同时也会被子命令的子命令所继承
//适用于全局性质的选项
2、local //特定选项 只允许给特定的子命令去添加选项
//语法1 添加一个选项为foo,默认值为空,说明信息
//将这个信息赋予给Foo的变量
Foo = testCmd.PersistentFlags().String("foo", "", "A help for foo")
//语法2 先定义变量,再以指针的形式进行传递
var Print string
testCmd.PersistentFlags().StringVar(&Print, "print", "", "print")
//语法3 定义多个选项为相同功能,--show/-s
//默认值为false,其他同上
testCmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show")
以上选项的定义,必须写入在当前子命令的init函数体内才会被使用
并且,这些使用的变量,必须提前在全局定义后才可调用
//这个和上面的基本类似
//--showL / -S 如果后面有定义该选项则为true,如果没有定义则为false
showL = *testCmd.Flags().BoolP("showL", "S", false, "show")
//同上 语法不同
testCmd.Flags().StringVar(&PrintL, "printL", "", "print")
//同上 语法不同
FooL = testCmd.Flags().String("fooL", "", "A help for foo")
get.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
//全局性选项变量
Foo *string
Print string
show bool
//本地性选项变量
PrintL string
FooL *string
showL *bool
)
var getCmd = &cobra.Command{
Use: "get",
Short: "我是短提示信息",
Long: `我是长提示信息`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(*(Foo)) //因为下面接收的是指针类型,所以这里做下格式化输出
fmt.Println(*(FooL))
fmt.Println(Print)
fmt.Println(PrintL)
if show {fmt.Println("Show")} //只能接收bool类型,当接收到true时,输出结果
if *(showL) {fmt.Println("ShowL")}
},
}
func init() {
rootCmd.AddCommand(getCmd)
//定义全局性选项
Foo = getCmd.PersistentFlags().String("foo", "", "A help for foo")
getCmd.PersistentFlags().StringVar(&Print, "print", "", "print")
getCmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show")
//定义本地性选项
FooL = getCmd.Flags().String("fooL", "", "A help for foo")
getCmd.Flags().StringVar(&PrintL, "printL", "", "print")
showL = getCmd.Flags().BoolP("showL", "d", false, "show")
}
go run main.go get --foo=foo1 --fooL=foo2 --print=haha --printL=haha2 -s=true -d=true
返回
foo1
foo2
haha
haha2
Show
ShowL
我这边为了模拟K8的命令格式,在get子命令下再添加一个node的子命令
cobra add node -p getCmd //-p 后面的是上层子命令所定义的变量名
NoArgs //如果存在任何位置参数,该命令将报错
ArbitraryArgs //该命令会接受任何位置参数
OnlyValidArgs //如果有任何位置参数不在命令的 ValidArgs 字段中,该命令将报错
MinimumNArgs(int) //至少要有 N 个位置参数,否则报错
MaximumNArgs(int) //如果位置参数超过 N 个将报错
ExactArgs(int) //必须有 N个位置参数,否则报错
ExactValidArgs(int) //必须有 N 个位置参数,且都在命令的 ValidArgs 字段中,否则报错
RangeArgs(min, max) //如果位置参数的个数不在区间 min 和 max 之中,报错
这里在get.go添加一个"MinimumNArgs(1)"参数,要求至少要携带一个参数才能使用
也就是说我们使用get后必须要指定查询的资源,不然是无意义的
get.go
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
//全局性选项变量
Foo *string
Print string
show bool
//本地性选项变量
PrintL string
FooL *string
showL *bool
)
var getCmd = &cobra.Command{
Use: "get",
Args: cobra.MinimumNArgs(1), //添加
Short: "我是短提示信息",
Long: `我是长提示信息`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(*(Foo))
fmt.Println(*(FooL))
fmt.Println(Print)
fmt.Println(PrintL)
if show {fmt.Println("Show")}
if *(showL) {fmt.Println("ShowL")}
},
}
func init() {
rootCmd.AddCommand(getCmd)
Foo = getCmd.PersistentFlags().String("foo", "", "A help for foo")
getCmd.PersistentFlags().StringVar(&Print, "print", "", "print")
getCmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show")
FooL = getCmd.Flags().String("fooL", "", "A help for foo")
getCmd.Flags().StringVar(&PrintL, "printL", "", "print")
showL = getCmd.Flags().BoolP("showL", "d", false, "show")
}
不带子参数运行
go run main.go get
携带子参数运行