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
  • 能够设置必备参数(必填的参数)
go 复制代码
//以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框架自行编写命令行工具

一个简单的开始

go 复制代码
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)

go 复制代码
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最哇塞的一个功能

go 复制代码
func setalias(f *pflag.FlagSet) {
//将所有参数名带-的,使用.也是一样的识别,这里name是参数原始名,返回的是别名。
	f.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
		return pflag.NormalizedName(strings.ReplaceAll(name, "-", "."))
	})
}

最终演示代码

go 复制代码
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())
	}
}



相关推荐
阿祖zu39 分钟前
芝士就是力量!开源私有化部署与 GitHub 双向同步的个人知识笔记 App
前端·后端·ios
松仔log1 小时前
Java中级——组合和继承
android·java·开发语言
不才不才不不才1 小时前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring
IT_陈寒1 小时前
SpringBoot自动配置失效?这个隐藏配置坑了我一整晚
前端·人工智能·后端
搜狐技术产品小编20231 小时前
告别“黑盒”与误判:如何用“多智能体对抗辩论”重构内容安全审核系统
后端·多agent
DantyWei2 小时前
controller注册及调用时机
后端
edwarddamon2 小时前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
码事漫谈2 小时前
我用 Seed Evolving 做了个 AI 小说写作工具
后端
Raas1002 小时前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
(Charon)3 小时前
【C++】锁与原子操作(四):自旋锁的完整实现与性能优化
c语言·开发语言·c++