Go学习笔记 : cobra 包简介

2023-11-18

cobra 是 go 语言的一个库,可以用于编写命令行工具。通常我们可以看到git pull 、docker container start 、apt install 等等这样命令,都可以很容易用corba来实现,另外,go 语言是很容易编译成一个二进制文件,本文将实现一个简单的命令行工具。

主要功能

cobra 的主要功能如下,可以说每一项都很实用:

  • 简易的子命令行模式,如 app server, app fetch 等等
  • 完全兼容 posix 命令行模式
  • 嵌套子命令 subcommand
  • 支持全局,局部,串联 flags
  • 使用 cobra 很容易的生成应用程序和命令,使用 cobra create appname 和 cobra add cmdname
  • 如果命令输入错误,将提供智能建议,如 app srver,将提示 srver 没有,是不是 app server
  • 自动生成 commands 和 flags 的帮助信息
  • 自动生成详细的 help 信息,如 app help
  • 自动识别帮助 flag -h,--help
  • 自动生成应用程序在 bash 下命令自动完成功能
  • 自动生成应用程序的 man 手册
  • 命令行别名
  • 自定义 help 和 usage 信息
  • 可选的与 viper apps 的紧密集成

cobra 中的主要概念

cobra 中有个重要的概念,分别是 commands、arguments 和 flags。其中 commands 代表行为,arguments 就是命令行参数(或者称为位置参数),flags 代表对行为的改变(也就是我们常说的命令行选项)。执行命令行程序时的一般格式为:
APPNAME COMMAND ARG --FLAG
比如下面的例子:

# server是 commands,port 是 flag
hugo server --port=1313

# clone 是 commands,URL 是 arguments,brae 是 flag
git clone URL --bare

如果是一个简单的程序(功能单一的程序),使用 commands 的方式可能会很啰嗦,但是像 git、docker 等应用,把这些本就很复杂的功能划分为子命令的形式,会方便使用(对程序的设计者来说又何尝不是如此)。

创建 cobra 应用

在创建 cobra 应用前需要先安装 cobra 包:    go get -u github.com/spf13/cobra/cobra

然后就可以用 cobra 程序生成应用程序框架了:   cobra init --pkg-name cobrademo  [在cobrademo目录下执行]

使用 cobra 程序生成命令代码

除了生成应用程序框架,还可以通过 cobra add 命令生成子命令的代码文件,比如下面的命令会添加两个子命令 image 和 container 相关的代码文件:  cobra add image 和 cobra add container

这两条命令分别生成了 cobrademo 程序中 image 和 container 子命令的代码,当然了,具体的功能还得靠我们自己实现。

为命令添加具体的功能

到目前为止,我们一共为 cobrademo 程序添加了三个 Command,分别是 rootCmd(cobra init 命令默认生成)、imageCmd 和 containerCmd。
打开文件 root.go ,找到变量 rootCmd 的初始化过程并为之设置 Run 方法:

Run: func(cmd *cobra.Command, args []string) {
    fmt.Println("cobra demo program")
},

重新编译 cobrademo 程序并不带参数运行【初次要执行 go mod init】,这次就不再输出帮助信息了,而是执行了 rootCmd 的 Run 方法:

D:\Project\GoProject\src\cobrademo>go build -o .

D:\Project\GoProject\src\cobrademo>cobrademo.exe
cobra demo program

再创建一个 version Command 用来输出当前的软件版本。先在 cmd 目录下添加 version.go 文件[ cobra add version],编辑文件的内容如下:

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

func init() {
    rootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
    Use:   "version",
    Short: "Print the version number of cobrademo",
    Long:  `All software has versions. This is cobrademo's`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("cobrademo version is v1.0")
    },
}
D:\Project\GoProject\src\cobrademo>go run main.go version
cobrademo version is v1.0

为 Command 添加选项(flags)

选项(flags)用来控制 Command 的具体行为。根据选项的作用范围,可以把选项分为两类:

  • persistent
  • local

对于 persistent 类型的选项,既可以设置给该 Command,又可以设置给该 Command 的子 Command。对于一些全局性的选项,比较适合设置为 persistent 类型,比如控制输出的 verbose 选项:

var Verbose bool
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")

local 类型的选项只能设置给指定的 Command,比如下面定义的 source 选项:

var Source string
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")

该选项不能指定给 rootCmd 之外的其它 Command。
默认情况下的选项都是可选的,但一些用例要求用户必须设置某些选项,这种情况 cobra 也是支持的,通过 Command 的 MarkFlagRequired 方法标记该选项即可:

var Name string
rootCmd.Flags().StringVarP(&Name, "name", "n", "", "user name (required)")
rootCmd.MarkFlagRequired("name")

命令行参数(arguments)

首先我们来搞清楚命令行参数(arguments)与命令行选项的区别(flags/options)。以常见的 ls 命令来说,其命令行的格式为:
ls [OPTION]... [FILE]…
其中的 OPTION 对应本文中介绍的 flags,以 - 或 -- 开头;而 FILE 则被称为参数(arguments)或位置参数。一般的规则是参数在所有选项的后面,上面的 … 表示可以指定多个选项和多个参数。

cobra 默认提供了一些验证方法:

  • NoArgs - 如果存在任何位置参数,该命令将报错
  • ArbitraryArgs - 该命令会接受任何位置参数
  • OnlyValidArgs - 如果有任何位置参数不在命令的 ValidArgs 字段中,该命令将报错
  • MinimumNArgs(int) - 至少要有 N 个位置参数,否则报错
  • MaximumNArgs(int) - 如果位置参数超过 N 个将报错
  • ExactArgs(int) - 必须有 N 个位置参数,否则报错
  • ExactValidArgs(int) 必须有 N 个位置参数,且都在命令的 ValidArgs 字段中,否则报错
  • RangeArgs(min, max) - 如果位置参数的个数不在区间 min 和 max 之中,报错

一个完整的 demo

我们在前面创建的代码的基础上,为 image 命令添加行为(打印信息到控制台),并为它添加一个子命令 cmdTimes,下面是更新后的 image.go 文件的内容:

package cmd

import (
	"fmt"
	"strings"

	"github.com/spf13/cobra"
)

// imageCmd represents the image command
var imageCmd = &cobra.Command{
	Use:   "image",
	Short: "Print images information",
	Long:  "Print all images information",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("image one is  win7")
		fmt.Println("image two is win10")
		fmt.Println("image args are : " + strings.Join(args, " "))
	},
}

var echoTimes int
var cmdTimes = &cobra.Command{
	Use:   "times [string to echo]",
	Short: "Echo anything to the screen more times",
	Long:  `echo things multiple times back to the user by providing a count and a string.`,
	Args:  cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		for i := 0; i < echoTimes; i++ {
			fmt.Println("Echo: " + strings.Join(args, " "))
		}
	},
}

func init() {
	rootCmd.AddCommand(imageCmd)
	cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
	imageCmd.AddCommand(cmdTimes)
}

编译后执行命令:

D:\Project\GoProject\src\cobrademo>go run main.go image hello
image one is  win7
image two is win10
image args are : hello

D:\Project\GoProject\src\cobrademo>go run main.go image times -t=3 world
Echo: world
Echo: world
Echo: world

D:\Project\GoProject\src\cobrademo>go run main.go image times -t=3
Error: requires at least 1 arg(s), only received 0
Usage:
  cobrademo image times [string to echo] [flags]

Flags:
  -h, --help        help for times
  -t, --times int   times to echo the input (default 1)

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

requires at least 1 arg(s), only received 0
exit status 1

D:\Project\GoProject\src\cobrademo>

因为我们为 cmdTimes 命令设置了 Args: cobra.MinimumNArgs(1),所以必须为 times 子命令传入一个参数,不然 times 子命令会报错:

帮助信息(help command)

cobra 会自动添加 --help(-h)选项,所以我们可以不必添加该选项而直接使用:


D:\Project\GoProject\src\cobrademo>go run main.go -h
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.

Usage:
  cobrademo [flags]
  cobrademo [command]

Available Commands:
  container   A brief description of your command
  help        Help about any command
  image       Print images information
  version     Print the version number of cobrademo

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.

cobra 同时还自动添加了 help 子命,默认效果和使用 --help 选项相同。如果为 help 命令传递其它命令作为参数,则会显示对应命令的帮助信息,下面的命令输出 image 子命令的帮助信息:

D:\Project\GoProject\src\cobrademo>go run main.go help image
Print all images information

Usage:
  cobrademo image [flags]
  cobrademo image [command]

Available Commands:
  times       Echo anything to the screen more times

Flags:
  -h, --help   help for image

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

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

当然也可以通过这种方式查看子命令的子命令的帮助文档:go run main.go help image times

除了 cobra 默认的帮助命令,我们还可以通过下面的方式进行自定义:

cmd.SetHelpCommand(cmd *Command)
cmd.SetHelpFunc(f func(*Command, []string))
cmd.SetHelpTemplate(s string)

提示信息(usage message)

提示信息和帮助信息很相似,只不过它是在你输入了非法的参数、选项或命令时才出现的,和帮助信息一样,我们也可以通过下面的方式自定义提示信息:

cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)

在 Commnad 执行前后执行额外的操作

Command 执行的操作是通过 Command.Run 方法实现的,为了支持我们在 Run 方法执行的前后执行一些其它的操作,Command 还提供了额外的几个方法,它们的执行顺序如下:
    1. PersistentPreRun
    2. PreRun
    3. Run
    4. PostRun
    5. PersistentPostRun
修改 rootCmd 的初始化代码如下:

var rootCmd = &cobra.Command{
    Use:   "cobrademo",
    Short: "sparkdev's cobra demo",
    Long: "the demo show how to use cobra package",
    PersistentPreRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
    },
    PreRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
    },
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Printf("cobra demo program, with args: %v\n", args)
    },
    PostRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
    },
    PersistentPostRun: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
    },
}

重新编译 cobrademo 程序并执行,输出结果中可以看到这些方法的执行顺序

D:\Project\GoProject\src\cobrademo>go run main.go
Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
cobra demo program, with args: []
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []

D:\Project\GoProject\src\cobrademo>go run main.go image hello
Inside rootCmd PersistentPreRun with args: [hello]
image one is  win7
image two is win10
image args are : hello
Inside rootCmd PersistentPostRun with args: [hello]

D:\Project\GoProject\src\cobrademo>

其中的 PersistentPreRun 方法和 PersistentPostRun 方法会伴随任何子命令的执行:

对未知命令的提示

如果我们输入了不正确的命令或者是选项,cobra 还会智能的给出提示,对于这样的提示我们也是可以自定义的,或者如果觉着没用就直接关闭掉。

参考:

https://www.cnblogs.com/sparkdev/p/10856077.html

https://xuchao918.github.io/2019/04/29/使用-go-cobra创建命令行项目/

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

Go学习笔记 : cobra 包简介 的相关文章

随机推荐

  • 08_STM32的存储结构

    STM32的存储器结构 存储器是单片机结构的重要组成部分 存储器是用来存储编译好的程序代码和数据的 有了存储器单片机系统才具有记忆功能 按照存储介质的特性 可以分 易失性存储器 和 非易失性存储器 两类 易失性存储器断电后 里面存储的内容会
  • 802.11K/V/R协议介绍

    802 11K V R协议介绍 1 传统无线漫游介绍 1 1 什么是无线漫游 一台无线终端备 STA 通过连接Wi Fi获取上网体验 Wi Fi名称 又称为SSID 是由无线接入网 AP 提供的 因为一台AP设备的覆盖范围有限 所以无线网络
  • 解决同时多个请求的处理问题,和定时任务

    应用场景 发布系统 让他晚上2点执行发布的一串任务 定时任务 更新访问量 晚上2点定时将数据从redis更新到mysql中去 商城类的抢购工作 大批量的用户涌入 承载不了一次性处理这么多的活儿 用这个方式也可以 目录结构 1 让woker运
  • maven项目debug查看依赖包源代码办法

    默认的maven工程 好像很难加载依赖的源代码 办法如下 maven调试时 无法进入源码 办法一 在debug配置里面 找到source 把带source的jar包 放进去 添加的时候 选add 再选external archive 这里要
  • jQuery——前端技术栈

    1 jQuery说明 jQuery 是一个 JavaScript 函数库 是一个轻量级的 写的少 做的多 的 JavaScript 库 jQuery 库包含以下功能 HTML 元素选取 HTML 元素操作 CSS 操作 HTML 事件函数
  • gin框架07--PureJSON

    gin框架07 PureJSON 介绍 案例 说明 介绍 通常 JSON 使用 unicode 替换特殊 HTML 字符 例如 lt 变为 u003c 如果要按字面对这些字符进行编码 则可以使用 PureJSON Go 1 6 及更低版本无
  • DataFrame入门丨Pandas数据分析基础(4)

    个人主页 互联网阿星 格言 选择有时候会大于努力 但你不努力就没得选 作者简介 大家好我是互联网阿星 和我一起合理使用Python 努力做时间的主人 如果觉得博主的文章还不错的话 请点赞 收藏 留言 支持一下博主哦 行业资料 PPT模板 简
  • Qt 6.x中Qt Quick简介及示例

    Qt Quick首次在Qt 4 7和Qt Creator 2 1中引入 是一种高级UI技术 Qt Quick模块是用于编写QML Qt Meta Object Language Qt元对象语言 应用程序的标准库 Qt QML模块提供了QML
  • Linux获取本机的IP的几种方式

    共计五条命令 使用的方式都不同 但原理相同充分利用LInux管道技术 root vagrant centos65 ifconfig eth0 grep Bcast cut d f2 cut d f1 192 168 191 2 root v
  • 西门子PLC的编程工具是什么?

    西门子PLC编程工具主要有下面这几个 1 STEP 7 Simatic Manager STEP 7或者Simatic Manager是西门子PLC编程最常用的软件开发环境 它是一款强大的集成开发环境 可以用来编写 调试PLC编程代码 还可
  • 《基础篇第4章:vue2基础》:使用vue脚手架创建项目

    文章目录 4 1初始化脚手架 4 1 1说明 4 1 2具体步骤 4 1 3模板项目的结构 4 1 4 创建第一个vue项目分析index html组成部分 4 1 5render函数 4 1 6修改默认配置 本人其他相关文章链接 4 1初
  • ubuntu wget ERROR 403: Forbidden 错误

    解决办法 临时变更wget的UA wget U 浏览器的useragent 下载地址 永久变更Wget 未测试 修改配置文件 etc wgetrc 添加下面这一行 header User Agent 浏览器的useragent 上面这个配置
  • 【vue】vue history和hash用法和区别

    vue中模式选择 router gt index js const router new VueRouter mode history base process env BASE URL routes hash和history区别 1 ha
  • 彷徨

    1 什么是hbase HBASE是一个高可靠性 高性能 面向列 可伸缩的分布式存储系统 利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群 HBASE的目标是存储并处理大型的数据 更具体来说是仅需使用普通的硬件配置 就
  • 相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。

    题目描述 相传韩信才智过人 从不直接清点自己军队的人数 只要让士兵先后以三人一排 五人一排 七人一排地变换队形 而他每次只掠一眼队伍的排尾就知道总人数了 输入3个非负整数a b c 表示每种队形排尾的人数 a lt 3 b lt 5 c l
  • 贝叶斯优化优化参数,以Kmeans为例

    文章目录 步骤一 构造黑盒目标函数 步骤二 确定取值空间 步骤三 构造贝叶斯优化器 全部代码 贝叶斯优化有几个步骤 构造黑盒目标函数 确定取值空间 构造贝叶斯优化器 下面以kmeans为例 步骤一 构造黑盒目标函数 这个函数主要是运行需要的
  • Git笔记

    一 安装Git Win10 直接到Git官网下载安装程序 按照默认选项安装即可 安装完成后 在开始菜单里找到Git gt Git Bash 打开弹出类似命令行的窗口 则说明Git安装成功 安装完成后还需要对Git进一步设置 在命令行输入 g
  • ubuntu18.04 git clone:Failed to connect to github.com port 443: Connection refused

    git clone问题记录 一 Failed to connect to github com port 443 Connection refused 1 问题 2 解决方法 3 参考博文 二 gnutls handshake failed
  • Golang并发安全和锁

    目录 场景 互斥锁 读写互斥锁 互斥锁 读写锁 Sync Once sync Map 定时器 场景 有时候在Go代码中可能会存在多个goroutine同时操作一个资源 临界区 这种情况会发生竞态问题 数据竞态 类比现实生活中的例子有十字路口
  • Go学习笔记 : cobra 包简介

    cobra 是 go 语言的一个库 可以用于编写命令行工具 通常我们可以看到git pull docker container start apt install 等等这样命令 都可以很容易用corba来实现 另外 go 语言是很容易编译成