cobra golang好用的CLI工具

2023-11-15

Cobra

每个好的开源项目都会有很多好用的开源库的诞生,之前学openstack的时候就对openstack的oslo系列工具组用的非常多,现在学习k8s后发现同样在go下也有很多类似的开源库,比如Cobra 就是一个用来创建命令行的 golang 库,同时也是一个用于生成应用和命令行文件的程序, 包括docker,k8s 都用的类似方式去实现,用于实现CLI非常好用,我的理解他有点类似openstack里的oslo.config。

概念:

Cobra 结构由三部分组成:命令 (commands)、参数 (arguments)、标志 (flags)。基本模型如下
比如git的命令或者kube-scheduler命令:

#git
git clone url --bare
# kube-scheduler
kube-scheduler --address=127.0.0.1 --leader-elect=true --kubeconfig=/etc/kubernetes/scheduler.conf
  • git :根命令
  • clone: 子命令
  • url: 参数args
  • –bare : flag,用于修饰这条命令的一些描述或者约束

安装

安装前请指定后$GOBIN路径,不然安装会失败

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

PS:安装失败一般是熟悉的网络问题,请先cd到$GOPATH/src/golang.org/x目录下用 git clone 下载 sys 和 text 项目

git clone https://github.com/golang/text
git clone https://github.com/golang/sys

然后执行go install github.com/spf13/cobra/cobra, 安装后在 $GOBIN 下出现了 cobra 可执行程序

使用

  • 初始化项目:
cobra init --pkg-name /root/go/src/study/cobrademo

新版本必须加参数 --pkg-name 。老版本直接cobra init projectname即可

当前的目录结构:

[root@dev001 cobrademo]# pwd

/root/go/src/study/cobrademo

[root@dev001 cobrademo]# tree

.

├── cmd

│ ├── root.go

├── LICENSE

└── main.go

看以下main.go的代码, 就是调用cmd,然后执行execute方法

package main

import "study/cobrademo/cmd"

func main() {
 cmd.Execute()
}

看下cmd下的root.go:

package cmd

import (
 "fmt"
 "github.com/spf13/cobra"
 "os"
 homedir "github.com/mitchellh/go-homedir"
 "github.com/spf13/viper"
)

var cfgFile string

// 根命令,cobrademo的结构体
var rootCmd = &cobra.Command{
 Use: "cobrademo",
 Short: "A brief description of your application", // 短描述
 Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. 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("start fabrademo project\n")
 },
}

func Execute() {
 if err := rootCmd.Execute(); err != nil {
  fmt.Println(err)
  os.Exit(1)
 }
}

func init() {
 cobra.OnInitialize(initConfig)
 rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobrademo.yaml)")
 rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

func initConfig() {
 if cfgFile != "" {
  viper.SetConfigFile(cfgFile)
 } else {
  home, err := homedir.Dir()
  if err != nil {
   fmt.Println(err)
   os.Exit(1)
  }
  viper.AddConfigPath(home)
  viper.SetConfigName(".cobrademo")
 }

 viper.AutomaticEnv()
 if err := viper.ReadInConfig(); err == nil {
  fmt.Println("Using config file:", viper.ConfigFileUsed())
 }
}

代码也很简单,可以看到具体执行的代码块就在Run: func(***) 这里, 后续添加command只要在rootcmd下建立子集即可

  • Commands

默认建的commands都在在根command下的同级command,需要手动修改所属关系

root.go 标记的是项目的根命令,接下来添加2个子命令

cobra add create
cobra add delete

在cmd 下面可以看到有个新文件create.go delete.go
修改create.go 代码如下

package cmd
import (
 "fmt"
 "github.com/spf13/cobra"
)

var createCmd = &cobra.Command{
 Use: "create",
 Short: "Short Desc For Create",
 Long: `Long Desc For Create`,
 Run: func(cmd *cobra.Command, args []string) {
 fmt.Println("create called")
 },
}

func init() {
 rootCmd.AddCommand(createCmd) // 这里表示优先级,即createcmd是rootcmd的子集
}

执行main.go:

go run main.go -h 
A Long Brief
Usage:
  cobrademo [flags]
  cobrademo [command]

Available Commands:
  create A brief description of your command
  delete A brief description of your command
  help Help about any command

Flags:
      --config string config file (default is $HOME/.cobrademo.yaml)
  -h, --help help for cobrademo
  -t, --toggle Help message for toggle

Use "cobrademo [command] --help" for more information about a command.

可以看到Available Commands 多了2个子命令集,且这2个命令是同级的
在create 里在添加一个子命令:

cobra add role

修改role.go

package cmd
import (
        "fmt"
        "github.com/spf13/cobra"
)

var roleCmd = &cobra.Command{
        Use: "role",
        Short: "short role",
        Long: `long role`,
        Run: func(cmd *cobra.Command, args []string) {
                fmt.Println("role called")
        },
}

func init() {
        createCmd.AddCommand(roleCmd)
}

将role 命令作为create命令的子命令,即在init下面修改为createCmd
运行main.go:

go run main.go create -h
A longer description that spans multiple lines and likely contains examples

Usage:
  cobrademo create [flags]
  cobrademo create [command]

Available Commands:
  role short role

Flags:
  -h, --help help for create

Global Flags:
      --config string config file (default is $HOME/.cobrademo.yaml)

Use "cobrademo create [command] --help" for more information about a command.

go run main.go create role
role called
  • Arguments

在command下进行参数配置,一般写cli对于参数配置无非用if … len(args)判断下参数数量,cobra内置了几个验证的方法,内置的验证方法如下:

  • NoArgs:如果有任何参数,命令行将会报错
  • ArbitraryArgs: 命令行将会接收任何参数
  • OnlyValidArgs: 如果有如何参数不属于 Command 的 ValidArgs 字段,命令行将会报错
  • MinimumNArgs(int): 如果参数个数少于 N 个,命令行将会报错
  • MaximumNArgs(int): 如果参数个数多于 N 个,命令行将会报错
  • ExactArgs(int): 如果参数个数不等于 N 个,命令行将会报错
  • RangeArgs(min, max): 如果参数个数不在 min 和 max 之间, 命令行将会报错

修改role.go:

package cmd

import (
        "fmt"
        "github.com/spf13/cobra"
)

var roleCmd = &cobra.Command{
        Use: "role",
        Short: "short role",
        Long: `long role`,
        Args: cobra.ExactArgs(1),
        Run: func(cmd *cobra.Command, args []string) {
                fmt.Printf("create role name: %s", args[0])
        },
}

func init() {
        createCmd.AddCommand(roleCmd)
}

执行main对应参数,并尝试参数数量修改:

go run main.go create role barney
create role name: barney

go run main.go create role barney ken
Error: accepts 1 arg(s), received 2
Usage:
  cobrademo create role [flags]

Flags:
  -h, --help help for role

Global Flags:
      --config string config file (default is $HOME/.cobrademo.yaml)

accepts 1 arg(s), received 2
exit status 1
  • Flag

但在实际使用中,直接加arg的方式并不好用,args的作为数组的方式传入,对传入顺序也有要求,没有办法像map那样做匹配,所以可以使用flag进行匹配,flag分为2类:

  • persistent
    该flag是一个全局flag,常见的比如verbose,在任何command(无论是根command还是子command下)都可以使用
  • localflag
    该flag 直接作用于单个command下
/* persistent flag */
// 定义变量
var verbose bool
// 参数分别表示变量取地址,flag名,缩写flag名,默认值,帮助
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")

/* local flag */
var name string
roleCmd.Flags().StringVarP(&name, "name", "n", "", "role name")

一般情况下都是使用StringVarP 用来接收类型为字符串变量的标志. 相较StringVar, StringVarP 支持标志短写. 以我们的 CLI 为例:在指定标志时可以用 --name,也可以使用短写 -n

修改后的role.go:

package cmd
import (
        "fmt"
        "github.com/spf13/cobra"
)

// 添加变量 name
var name string
var roleCmd = &cobra.Command{
        Use: "role",
        Short: "short role",
        Long: `long role`,
        //Args: cobra.ExactArgs(1),
        Run: func(cmd *cobra.Command, args []string) {
          // 如果没有flag输入的情况下
          if len(name) == 0 {
            cmd.Help()
            return
          }

        fmt.Printf("create role name: %s \n", name)
        },
}

func init() {
        createCmd.AddCommand(roleCmd)
        // 添加本地标志
        roleCmd.Flags().StringVarP(&name, "name", "n", "", "role name")
}

执行main.go:


go run main.go create role
Usage:
  cobrademo create role [flags]

Flags:
  -h, --help help for role
  -n, --name string role name

Global Flags:
      --config string config file (default is $HOME/.cobrademo.yaml)

# 可以看到分了flag 和默认的global flag,globalflag因为用的是rootCmd.PersistentFlags().StringVar ,所以没有缩写

go run main.go create role --name=barney
create role name: barney

最后的global是cobra创建project后自带的,默认使用的yaml的配置文件方式,默认位置也在$HOME/.cobrademo.yaml 下,看到这里第一反应就是kubectl的~/.kube/config配置文件,所以看完了cobra再去看kubernetes,会发现非常熟悉

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cobra golang好用的CLI工具 的相关文章

  • GOMAXPROCS 默认值是多少?

    不设置同名环境变量时是否保证GOMAXPROCS设置为1 此代码显示的值 package main import runtime fmt func getGOMAXPROCS int return runtime GOMAXPROCS 0
  • 如何将 int[] 转换为 uint8[]

    所以 我需要你的帮助 我找不到关于该主题的任何内容 Golang 是一门刚刚诞生的语言 所以对于像我这样的新手来说很难快速找到答案 预先声明的 Goint类型大小是特定于实现的 32 位或 64 位 数字类型 http golang org
  • 如何读取大型平面文件

    我有一个平面文件 其中包含 339276 行文本 大小为 62 1 MB 我试图读入所有行 根据我所拥有的某些条件解析它们 然后将它们插入数据库 我最初尝试使用 bufio Scan 循环和 bufio Text 来获取该行 但缓冲区空间不
  • 与通道相比,sync.WaitGroup 的优势是什么?

    我正在开发一个并发 Go 库 我偶然发现了 goroutine 之间两种不同的同步模式 其结果相似 等待组 https play golang org p ZYPLlcp16TZ package main import fmt sync t
  • 在 Go to 函数中通过引用和值传递

    我对 Go 中通过引用和值传递有点困惑 我已经看到过对类型前面的 的解释 在类型名称前面 表示声明的变量将存储该类型的另一个变量的地址 而不是该类型的值 类型 这对我来说毫无意义 在Java中 如果我将数据库实例传递给函数 我会这样做 da
  • 错误:标准包中非标准导入“gopkg.in/yaml.v2”

    我正在尝试从以下位置导入 go yamlhttps github com go yaml yaml https github com go yaml yaml 并且我发现了一个 Google 没有提供帮助的错误 I ran go get g
  • 在 Golang 中运行外部 python,捕获连续的 exec.Command Stdout

    所以我的 go 脚本将像这样调用外部 python cmd exec Command python game py cmd Stdout os Stdout cmd Stderr os Stderr go func err cmd Run
  • Golang 中的确定性 RSA 加密 - 如何在多次加密下为给定消息获得相同的结果

    对于下面的RSA加密代码 每次对同一条消息进行加密时 结果都会不同 我发现这是由于rand Reader in the rsa EncryptOAEP功能使其更加安全doc https pkg go dev crypto rsa Encry
  • 在复杂的文件夹结构中进行测试

    我正在 golang 中构建一个设计模式存储库 为了运行所有测试 我使用这个 bash 脚本 有用 bin bash go test creational abstract factory go go test creational bui
  • pprof 和 ps 之间的内存使用差异

    我一直在尝试分析用 cobra 构建的 cli 工具的堆使用情况 这pprof工具显示如下 Flat Flat Sum Cum Cum Name Inlined 1 58GB 49 98 49 98 1 58GB 49 98 os Read
  • “http:多个response.WriteHeader调用”有什么不好的影响?

    尽管我发现 http 多个响应 WriteHeader 调用 例外 但我的服务器表现良好 此异常不会导致我的服务器出现恐慌或行为异常 我进行了很多搜索 但只找到了如何解决这个问题 没有文档描述异常的不良影响 有人可以帮我找出为什么 http
  • 运行最新版本时没有“最新”消息?

    我正在尝试使用Sparkle https sparkle project org与 Qt Go 的绑定 https github com therecipe qt app 闪光 m import
  • 如何对结构切片而不是切片结构进行范围调整

    稍微玩了一下 Go HTML 模板后 我发现的所有循环模板中对象的示例都是将切片结构传递给模板 有点像这个示例 type UserList struct Id int Name string var templates template M
  • 云存储 API 的错误导入“系统调用”

    我正在按照以下说明进行操作https cloud google com appengine docs go googlecloudstorageclient download开始将一些代码从现已弃用的文件 API 迁移到新的 Cloud S
  • 如何将长 Go 模板函数拆分为多行?

    我有一个很长的printf调用 Go 模板 例子 printf mongodb s s s s authSource admin replicaSet s readPreference nearest w majority Values r
  • 从 Golang 调用 C 函数

    我想在 Golang 中编写控制器逻辑并处理 json 和数据库 同时在 C 中使用我的数学处理模型 在我看来 调用 C 函数的开销必须尽可能低 就像设置寄存器 rcx rdx rsi rdi 一样 执行一些操作fastcall 并获取 r
  • 如何在golang中获得两个切片的交集?

    Go 中有没有有效的方法来获取两个切片的交集 我想避免嵌套 for 循环之类的解决方案slice1 string foo bar hello slice2 string foo bar intersection slice1 slice2
  • 子字符串和 Go 垃圾收集器

    在 Go 中获取字符串的子字符串时 不会分配新的内存 相反 子字符串的底层表示包含一个数据指针 该指针是原始字符串的数据指针的偏移量 这意味着 如果我有一个大字符串并希望跟踪一个小子字符串 则垃圾收集器将无法释放任何大字符串 直到我释放对较
  • 如何在 Go 中获取给定月份的第一个星期一?

    我正在尝试获取给定月份的第一个星期一 我能想到的最好方法是循环前 7 天 然后返回 Weekday Monday 有一个更好的方法吗 通过查看时间的 Weekday 您可以计算出第一个星期一 package main import fmt
  • 如何在 Go 中使用与包同名的变量名?

    文件或目录的常见变量名称是 path 不幸的是 这也是 Go 中包的名称 此外 在 DoIt 中更改路径作为参数名称 如何编译此代码 package main import path os func main DoIt file txt f

随机推荐

  • 非对称加密-RSA

    一 非对称加密 1 对称加密 对称密码的核心是一把密钥 使用相同的密钥进行加密和解密 如移位密码 S DES 但密匙本身也是信息 对称密码中它的安全得不到保障 2 非对称加密 非对称密码的核心是公钥和私钥 公钥是用于加密数据的密钥 而私钥则
  • Python报错集合篇5-FileNotFoundError: [Errno 2] No such file or directory: '不存在的文档.txt'

    本文介绍如何处理报错 FileNotFoundError Errno 2 No such file or directory 不存在的文档 txt 源代码 f open 不存在的文档 txt print f read f close 运行报
  • Unity_UGUI_Image的图层遮挡问题_渲染层级

    有时候 创建图片 图片会被遮挡 如何改变 图片不被遮挡呢 只需要改变图片的层级就可以了 把要显示在 上面的Image 变为遮挡它的 image的子物体就可以了 或者 把要显示在上面的Image 放在下面 渲染层级 1 Camera 相机 D
  • MySQL单行函数

    目录 1 数值函数 2 字符串函数 3 日期和时间函数 3 1 获取日期 时间 3 2 日期与时间戳的转换 3 3 获取月份 星期 星期数 天数等函数 3 4 日期的操作函数 3 5 时间和秒钟转换的函数 3 6 计算日期和时间的函数 3
  • 持续集成工具Jenkins安装及Jenkins离线状态解决

    使用的虚拟机是centos6 1 前置条件 虚拟机已安装jdk和Tomcat 这里只介绍安装Tomcat 安装jdk网上版本很多 大家可以自行查阅 2 安装Tomcat 1 下载地址 https tomcat apache org down
  • Stream流的常用方法(自用)

    自用的笔记 有 需要多看 基本数据 自定义实体 Data class Student private String name private Integer age private Double height public Student
  • 机器学习处理问题的基本路线

    基本路线 1 搭建环境 数据读入 2 数据分析 3 特征工程 4 建模调参 5 模型融合 异常处理 通过箱线图 或 3 Sigma 分析删除异常值 BOX COX 转换 处理有偏分布 长尾截断 特征筛选常用方法 过滤式 filter 先对数
  • Acwing-包含min函数的栈

    stk表示存入这些数据的栈 stk min表示栈里面前i数中的最小值是多少 class MinStack public stack
  • 第二十五篇:UE4如何通过http方式请求接口Json数据

    本篇介绍UE4如何向接口请求数据并解析数据 首先我们需要用到两个插件VaRest和Json Blueprint 这两个插件都是免费的 在虚幻商城可以免费获取到 两个插件安装到UE4引擎之后 新建一个工程 开启这两个插件 记下来介绍两种接口请
  • 教学:四步利用PHP study小皮面板在vscode上编辑php并运行

    第一步 安装完PHP study 需要自行安装phpstudy和vscode 不会的问度娘 第二步 下载xdebug xdebug下载地址 http xdebug org download 这里我是把PHP study安装到我的Window
  • 人大金仓数据库-kingbaseES

    KingbaseES数据库是一个大型通用的跨平台系统 可以安装和运行于Windows Linux UNIX等多种操作系统平台下 KingbaseES数据库在各种操作系统平台上都很容易安装和配置 用户可以参考相应平台下的安装指南 安装King
  • 如何使用CSS实现一个带有动画效果的折叠面板(Accordion)?

    聚沙成塔 每天进步一点点 专栏简介 折叠面板 Accordion 带动画效果 写在最后 专栏简介 前端入门之旅 探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅 这个专栏是为那些对W
  • 【leetcode算法】02-两数之和

    目录 1 题目描述 2 解题思路 第一种解法 暴力枚举 第二种解法 哈希映射 3 代码展示 4 小结 前言 声明 本文仅为学习记录 图片以及题目资源来自牛客和力扣网 如有侵权请联系删除 大家好 我是尼根 一个又菜又想学算法的准程序猿 今天为
  • 数据分析 -- Pandas①

    目录 Pandas简介 Pandas中的两个主要数据结构 Series 创建 访问 DataFrame 创建 列的查改增删 查看列 修改列 新增列 删除列 导入 导出 表格文件以及常规操作 head 方法 tail 方法 info 方法 d
  • path png转svg_svg之path详解

    一 svg 介绍 path元素是SVG基本形状中最强大的一个 它不仅能创建其他基本形状 还能创建更多其他形状 你可以用path元素绘制矩形 直角矩形或者圆角矩形 圆形 椭圆 折线形 多边形 以及一些其他的形状 例如贝塞尔曲线 2次曲线等曲线
  • 解决java.net.SocketException: No buffer space available (maximum connections reach

    严重 Catalina stop java net SocketException No buffer space available maximum connections reached JVM Bindat java net Plai
  • 断网重启路由器就好_路由器间断性的无网络,重启就恢复正常,可能是这些原因导致的!...

    说到 互联网 这一个词 相信大家对它再熟悉不过了 早在互联网刚出来的时候 人们就被它那强大的 引力 给吸引过去 直到现在 互联网已成为人们可以加以利用的一种 道具 了 现如今的我们可以通过网络来了解到一些国内外最新的热点资讯 可以通过网络来
  • 局域网抓包分析工具_巧用Wireshark抓包工具,分析底层网络协议,帮助排除网络故障...

    地址解析协议 ARP Address Resolution Protocol 1 ARP头 2 数据包分析 长度 8 位 字节 MAC 地址 48 位 即 6 字节 IP 地址 32 位 即 4 字节 3 无偿的 ARP 当 IP 地址改变
  • 如何使用PT对电路进行功耗分析

    首先声明本文所讲的范围 在这篇文章中 是采用synopsys的设计流程 对数字电路进行功耗分析 生成功耗分析报告的流程 分析的对象是逻辑综合之后布局布线之前的功耗分析 以及布局布线之后的功耗分析 Synopsys做功耗分析使用到的工具是 P
  • cobra golang好用的CLI工具

    Cobra 每个好的开源项目都会有很多好用的开源库的诞生 之前学openstack的时候就对openstack的oslo系列工具组用的非常多 现在学习k8s后发现同样在go下也有很多类似的开源库 比如Cobra 就是一个用来创建命令行的 g