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())
	}
}



相关推荐
程序员岳焱4 分钟前
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
后端·sql·mysql
龚思凯10 分钟前
Node.js 模块导入语法变革全解析
后端·node.js
天行健的回响13 分钟前
枚举在实际开发中的使用小Tips
后端
wuhunyu18 分钟前
基于 langchain4j 的简易 RAG
后端
techzhi19 分钟前
SeaweedFS S3 Spring Boot Starter
java·spring boot·后端
过河不拆乔1 小时前
AWS 公开数据集下载与操作说明
学习·云计算·aws
写bug写bug1 小时前
手把手教你使用JConsole
java·后端·程序员
苏三说技术1 小时前
给你1亿的Redis key,如何高效统计?
后端
JohnYan2 小时前
工作笔记- 记一次MySQL数据移植表空间错误排除
数据库·后端·mysql