Golang学习(二十七)强大的命令行工具cobra

corba命令行解析工具,在看K8代码的时候发现有很多地方都用到了,这里说一下

 项目地址

https://github.com/spf13/cobra

一、命令行工具基本概念

1、命令行工具的格式

[appName] [command] [arguments] --[flag]
执行文件     动作        数值       参数


1、appName     //执行文件本身,就是main.exe
1、commands    //行为,具体操作的动作 比如K8的 get  logs操作
2、arguments   //表示数值
3、flags       //表示对行为的改变

2、环境安装

go get -u github.com/spf13/cobra/cobra

3、命令行工具初始化

cobra init tools   //初始化目录

Golang学习(二十七)强大的命令行工具cobra_第1张图片

覆盖配置

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的模板文件

Golang学习(二十七)强大的命令行工具cobra_第2张图片

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的所有操作方法,在主体命令下层
}

 

测试

Golang学习(二十七)强大的命令行工具cobra_第3张图片

 可以看到,在主体命令下多了一个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、 选项分类

1、persistent  //永久选项,它可以给子命令添加选项,同时也会被子命令的子命令所继承
               //适用于全局性质的选项

2、local       //特定选项   只允许给特定的子命令去添加选项

2、两种选项的定义格式

选项1  persistent

//语法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函数体内才会被使用
并且,这些使用的变量,必须提前在全局定义后才可调用

选项2  local 

//这个和上面的基本类似
//--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")
}

测试

Golang学习(二十七)强大的命令行工具cobra_第4张图片

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

Golang学习(二十七)强大的命令行工具cobra_第5张图片

携带子参数运行

你可能感兴趣的:(GO,GO模块,golang,开发语言,后端)