要命!我篡改了系统命令惊现事故,竟要扣我年终奖-Golang-cobra

news2024/12/23 22:18:12
alt

打工还是要打工的。。我最后也没发出去。

紧急处理以后,现在写复盘,大家随我看看我到底是在学习哪些内容。

(以上内容纯属虚构,如有雷同纯属巧合)

简介

之前我们讲过pflag和os.Args,现在说说cobra这个命令行框架。

KubernetesHugoetcd 这些知名项目都用cobra来做命令行程序。学起来!

关于作者spf13,这里多说两句。spf13 开源不少项目,而且他的开源项目质量都比较高。相信使用过 vim 的都知道spf13-vim,号称 vim 终极配置。可以一键配置,对于我这样的懒人来说绝对是福音。

alt

还有他的viper是一个完整的配置解决方案。完美支持 JSON/TOML/YAML/HCL/envfile/Java properties 配置文件等格式,还有一些比较实用的特性,如配置热更新、多查找目录、配置保存等。还有非常火的静态网站生成器hugo也是他的作品牛人就是牛人。

这个牛人 https://github.com/spf13

快速使用

第三方库都需要先安装,后使用。下面命令安装了cobra生成器程序和 cobra 库:

$ go get github.com/spf13/cobra/cobra

PS: 如果出现了golang.org/x/text库找不到之类的错误,需要手动从 GitHub 上下载该库,再执行上面的安装命令。

现在要举的例子是让我们的程序调子命令时会透传到git上,用git version举例。目录结构如下(手动建的):

get-started/
    cmd/       
      root.go        
      version.go    
    utils/
      helper.go
    main.go
  • cmd目标是子命令列表,这里有一个 version命令。
  • root.go先卖个关子,大家不要理他。
  • main.go是主程序。
  • helper是这里使用到的工具类。
  • go.mod文件我省略了。

下面的代码文件我就省略import "github.com/spf13/cobra"了,大家知道就行,version.go文件:

var versionCmd = &cobra.Command{
 Use:   "version",
 Short: "version subcommand show git version info.",

 Run: func(cmd *cobra.Command, args []string) {
  output, err := utils.ExecuteCommand("git""version", args...)
  if err != nil {
   utils.Error(cmd, args, err)
  }

  fmt.Fprint(os.Stdout, output)
 },
}

func init() {
 rootCmd.AddCommand(versionCmd)
}
  • 几个参数含义是子命令名称、子命令短提示、子命令调用的方法
  • init()里把子命令加到主命令中去。

你会有疑惑rootCmd是哪来的吗?实际上我们需要一个根节点,把其他命令加进来。如下是root.go文件。

var rootCmd = &cobra.Command {
 Use: "git",
 Short: "Git is a distributed version control system.",
 Long: `Git is a free ...省略`,
 Run: func(cmd *cobra.Command, args []string) {
  utils.Error(cmd, args, errors.New("unrecognized command"))
 },
}

func Execute() {
 rootCmd.Execute()
}

有没有发现这里不是init()而是Execute()?这里此包唯一暴露的公开函数内容,专门供命令初始化使用。如下main.go文件中的调用命令入口:

import "cmd"
func main() {
  cmd.Execute()
}

最后为了编码方便,在helpers.go中封装了调用外部程序和错误处理函数,我就不展开写了,有兴趣去看我的源码。

https://github.com/golang-minibear2333/cmd_utils

cobra 自动生成的帮助信息,very cool

$ go run . -h
Git is a free and open source distributed version control system
designed to handle everything from small to very large projects 
with speed and efficiency.

Usage:
  git [flags]
  git [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  version     version subcommand show git version info.

Flags:
  -h, --help   help for git

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

单个子命令的帮助信息:

$ go run . version -h
version subcommand show git version info.

Usage:
  git version [flags]

Flags:
  -h, --help   help for version

调用子命令:

$ go run . version
git version 2.33.0

未识别的子命令:

$ go run . xxx
Error: unknown command "xxx" for "git"
Run 'git --help' for usage.

使用 cobra 构建命令行时,程序的目录结构一般比较简单,推荐使用下面这种结构:

appName/
    cmd/
        cmd1.go
        cmd2.go
        cmd3.go
        root.go
    main.go

每个命令实现一个文件,所有命令文件存放在cmd目录下。外层的main.go仅初始化 cobra。

特性

cobra 提供非常丰富的功能:

  • 轻松支持子命令,如 app serverapp fetch等;
  • 完全兼容 POSIX 选项(包括短、长选项);
  • 嵌套子命令;
  • 全局、本地层级选项。可以在多处设置选项,按照一定的顺序取用;
  • 使用脚手架轻松生成程序框架和命令。

首先需要明确 3 个基本概念:

  • 命令(Command):就是需要执行的操作;
  • 参数(Arg):命令的参数,即要操作的对象;
  • 选项(Flag):命令选项可以调整命令的行为。

比如

git clone URL --bare

clone 是一个(子)命令,URL 是参数,--bare是选项。子命令我们已经讲过了,现在讲讲参数。

参数

比如定义命令的地方。

var cloneCmd = &cobra.Command{
 Use:   "clone url [destination]",
  ...
  Run: func(cmd *cobra.Command, args []string) {
  ...

会改变帮助函数输出的内容。实际上还是传入字符串数组。

go run . clone -h
Clone a repository into a new directory

Usage:
  git clone url [destination] [flags]

Flags:
  -h, --help   help for clone

选项

cobra 中选项分为两种.

  • 一种是永久选项( PersistentFlags 翻译不太标准,暂时就说永久选项),定义它的命令和其子命令都可以使用。方法是给根命令添加一个选项定义全局选项。
  • 另一种是本地选项,只能在定义它的命令中使用。

cobra 使用pflag解析命令行选项,上次讲过,实际上用法都是一样的。

设置永久选项,在root.go根命令文件中的init()函数:

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

设置本地选项,在子命令的init()函数:

var(
  Source bool
)
func init() {
  localCmd.Flags().StringVarP(&Source, "source""s""""Source directory to read from")
  rootCmd.AddCommand(divideCmd)
}

两种参数都是相同的,长选项/短选项名、默认值和帮助信息。

脚手架

通过前面的介绍,我们也看到了其实 cobra 命令的框架还是比较固定的。这就有了工具的用武之地了,可极大地提高我们的开发效率。

在你的go root下安装cobra-cli,确保bin目录已经放到系统的path里,之前写的文章-运行那一节有提到过怎么操作,不记得的回去看看哈。

go install github.com/spf13/cobra-cli@latest

下面我们介绍如何使用这个生成器,先看命令帮助:

Usage:
  cobra-cli init [path] [flags]

Aliases:
  init, initialize, initialise, create

Flags:
  -h, --help   help for init

Global Flags:
  -a, --author string    author name for copyright attribution (default "YOUR NAME")
      --config string    config file (default is $HOME/.cobra.yaml)
  -l, --license string   name of license for the project
      --viper            use Viper for configuration
  • 根据提示子命令 init,可选参数为 path
  • 选项为 -a指定作者, --config string指定 cobra-cli自己的配置文件
  • -l指定 license--viper使用 viper来读取配置文件。

使用cobra init命令创建一个 cobra 应用程序:

$ mkdir appname
cd appname
$ cobra-cli init
Error: Please run `go mod init <MODNAME>` before `cobra-cli init`
$ go mod init
go: creating new go.mod: module github.com/golang-minibear2333/cmd_utils/git/appname
$ cobra-cli init
Your Cobra application is ready at
/Users/xxxx/Documents/code/go/src/github.com/golang-minibear2333/cmd_utils/git/appname
  • 先初始化 mod 再初始化项目
  • 其中 appname为应用程序名。生成的程序目录结构如下:
.
├── LICENSE
├── cmd
│   └── root.go
├── go.mod
├── go.sum
└── main.go

这个项目结构与之前介绍的完全相同,也是 cobra 推荐使用的结构。同样地,main.go也仅仅是入口。里面的英文注释非常的清晰,我一下子就看懂了用法,你也试试。

配置读取

除了命令行以外,这个库还可以用来配置读取,我们先创建项目和配置文件:

mkdir cfg_load && cd_cg_load
mkdir config && touch config/cfg.yaml
cat >config/cfg.yaml <<-EOF
people:
   name: minibear2333
   age: 18
EOF

PS: linux命令不熟的可以在Go群里问我。

现在我们尝试读取这个配置文件,直接使用命令来创建读取配置文件的代码。

$ cobra-cli init --viper
Your Cobra application is ready at
/Users/xxx/Documents/code/go/src/github.com/golang-minibear2333/cmd_utils/git/cfg_load

现在就创建了一个默认配置文件为$HOME/.cfg_load.yaml的命令行程序,而我们之前放在了另一个位置,所以启动的时候需要指定一下。

$ go run . --config==config/cfg.yaml

配置文件就成功载入了,现在你就可以用viper在需要的地方读取配置了。

为了展示一下配置是否成功读取,继续用cobra-cli来创建一个子命令。

$ cobra-cli add viperall

修改此子命令Run函数的内容为

var viperallCmd = &cobra.Command{
 Use:   "viperall",
 Short: "Show cfg all",
 Long: `Show the contents of the entire configuration file`,
 Run: func(cmd *cobra.Command, args []string) {
  fmt.Println(viper.AllSettings())
 },
}

运行,妥了。

$ go run . viperall --config=config/cfg.yaml 
Using config file: config/cfg.yaml
map[people:map[age:18 name:minibear2333]]

每次都要指定肯定很麻烦,你熟悉viper的话可以自己改一下默认文件,把我的项目下下来给我提交一个pr吧~!

子命令也可以嵌套,只需要在init()的时候,加到父命令里,当然也可以自动生成。

$ cobra-cli add tt -p viperallCmd
tt created at /Users/xxx/Documents/code/go/src/github.com/golang-minibear2333/cmd_utils/git/cfg_load
$ go run . viperall tt --config=config/cfg.yaml 
Using config file: config/cfg.yaml
tt called
  • 注意父命令是 viperall,但是 -p指定的时候要改为 viperallCmd,因为如下(我觉得这个是个很好的贡献pr,你可以建议作者改一下):
var viperallCmd = &cobra.Command{

小结

  • 每个 cobra 程序都有一个根命令,可以给它添加任意多个子命令。比如我们在 version.goinit函数中将子命令添加到根命令中。
  • 创建子命令时指定子命令名称、子命令短提示、子命令调用的方法。
  • 三个重要概念,子命令、参数、选项。
  • 全局选项和子命令自己使用的选项。
  • cobra-cli 自动创建项目,自动创建配置文件读取项目,自动增加子命令,自动增加嵌套子命令。

推荐目录结构

.
├── LICENSE
├── cmd
│   ├── root.go
|   ├── cmd1.go
├── go.mod
├── go.sum
└── main.go

还有更多! cobra 提供了非常丰富的特性和定制化接口,例如:

  • 设置钩子函数,在命令执行前、后执行某些操作。
  • 生成 Markdown/ReStructed Text/Man Page 格式的文档。
  • 等。自己下来学咯。

cobra 库的使用非常广泛,很多知名项目都有用到,前面也提到过这些项目。学习这些项目是如何使用 cobra 的,可以从中学习 cobra 的特性和最佳实践。这也是学习开源项目的一个很好的途径。

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何将SQL Server数据从表导出到CSV文件

在本文中,我们将使用四种不同的工具将表从SQL Server导出到.csv文件。此外,你将学习如何将带有或不带有头的SQL查询结果导出到.csv文件。 SQL Server数据从表导出到CSV文件 使用SQL Server Management Studio将SQL结果导出到具有或不具有标题的CSV文件一、不带标题二、带标题…

图形编辑器:图形和辅助线绘制的坐标问题

大家好&#xff0c;我是前端西瓜哥。今天看看绘制图形和辅助线时&#xff0c;坐标转换的一些注意点。 项目地址&#xff0c;欢迎 star&#xff1a; https://github.com/F-star/suika 线上体验&#xff1a; https://blog.fstars.wang/app/suika/ 先回顾一下之前讲的视口坐标和场…

docker镜像与容器实践

一、引子 镜像和容器是不同的概念&#xff0c;本文主要是为了通过实践来强化对这两种不同概念的理解。 二、安装docker 安装docker&#xff0c;执行以下命令即可&#xff1a; # 安装依赖 yum install -y yum-utils device-mapper-persistent-data lvm2 # 设置国内源 yum-co…

显示Linux系统上的服务

init 和 systemd 都是 Linux的 init 守护进程&#xff0c;systemd出现较晚&#xff0c;最近的 Linux 发行版中很常用。init 使用service命令管理服务&#xff0c;而Systemd用systemctl命令管理服务。init 和 systemd 都是 Linux的 init 守护进程&#xff0c;即使你的 Linux 系统…

Maven3.8.*系列 settings.xml详解

文章目录文末,拿完整Settings配置文件设置参考介绍简要概述设置详细信息简单的价值观插件组服务器密码加密的镜像代理配置文件激活性能库插件的储存库活动概况直达文末,拿完整Settings配置文件结语文末,拿完整Settings配置文件 设置参考 介绍 简要概述 的 settings 元素 set…

返乡上云图

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

PicGo+Github搭建图床

文章目录一、Github仓库创建二、配置PicGo三、实际体验四、PicGo 2.3.1参考资料一、Github仓库创建 PS&#xff1a;它只会显示一次&#xff0c;所以最好把它复制下来到你的备忘录存好&#xff0c;方便下次使用&#xff0c;否则下次有需要重新新建&#xff1b; 二、配置PicGo …

Linux进程控制(进程退出+进程等待)

目录 一、子进程创建 1.1 fork函数深入 1.2 写时拷贝 二、进程退出 2.1.1 进程退出码概念 2.1.2 系统退出码文字描述 2.1.3 _exit和exit函数 2.1.4 查看退出码 三、进程等待 3.1 进程等待解决僵尸进程 3.2 进程等待方法 3.2.1 wait 3.2.2 waitpid(&#xff09; 四、…

seata部署指南(v1.6.1)

Seata 搭建 db模式版本 V1.6.1一、 简介二、下载三、建表&#xff08;仅db&#xff09;四、配置 seata server 参数4.1、V1.4.2之前方式4.2、V1.4.2 之后推荐方式(seataServer.properties)五、配置Server5.1、 修改 appplication.yml5.1.1、 修改 appplication.yml seata.store…

文件操作(File类)

文章目录一、初识文件二、File类构造方法常用方法一、初识文件 我们目前是如何存储数据的?弊端是什么? int a 1; int[] arr new int[5];我们这些数据是在内存中存储的&#xff0c;是不能够长久保存的。 那么&#xff0c;我们的计算机当中有没有一块硬件可以长久存储数据…

PostgreSQL(一)Windows安装

目录一、下载二、安装PostgreSQL三、安装StackBuilder四、打开PostgreSQL管理工具pgAdmin五、打开命令行一、下载 下载地址&#xff1a; https://www.enterprisedb.com/downloads/postgres-postgresql-downloads 下载后安装包如下&#xff1a; 二、安装PostgreSQL 双击打开安…

DataX使用入门

DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS 等各种异构数据…

Java 日志框架 Log4J

文章目录引言什么是Log4JLog4J三大组件Log4J日志级别Log4J基本使用自定义配置文件Appender示例FileAppenderDailyRollingFileAppenderRollingFileAppenderJDBCAppender自定义Logger引言 Java 日志框架 JUL 在这篇文章中已经向大家介绍了我们为什么要使用日志文件、常见的日志…

张力调节(精密调节气阀应用)

跳舞轮对应张力调节范围&#xff0c;我们可以通过改变气缸的气压方式间接改变&#xff0c;张力跳舞轮在收放卷闭环控制上的详细应用&#xff0c;可以参看下面的文章链接&#xff0c;这里我们主要讨论精密可调气阀的模拟量编程问题。 PLC张力控制&#xff08;开环闭环算法分析&…

【实践向】当移除了三级缓存……

本文会手把手带你一起把使用二级缓存替换三级缓存&#xff0c;看下移除了三级缓存&#xff0c;只有二级缓存会出什么问题&#xff0c;用实践回答那个被问了无数次的“为什么要有三级缓存&#xff1f;”以及“二级缓存解决不了循环依赖问题吗&#xff1f;”等类似问题(&#xff…

“Flash配置不当漏洞”详解

危害 可被用来进行跨域访问&#xff0c;可能会导致“跨站点伪造请求”或“跨站点跟踪”&#xff08;“跨站点脚本编制”的变体&#xff09;之类的攻击&#xff0c;从而导致其它用户的信息被非法读取。 导致不受信任的第三方域的flash也能访问当前域的资源&#xff0c;绕过同源策…

一、构建自己的图像分类数据集(Datawhale组队学习)

文章目录安装配置环境图像采集采集函数爬取一类图片爬取多类图片一些参考类别的关键词制作图像分类数据集的注意事项删除多余文件删除系统自动生成的多余文件删除gif格式的图像文件删除非三通道的图像统计图像尺寸、比例分布采用的数据集统计数据集的基本信息可视化图像尺寸分布…

Embarcadero Dev-C++第一次使用注意事项

Embarcadero Dev-C第一次使用注意事项 Embarcadero Dev-C简介 2000年左右&#xff0c;Bloodshed software开发了Dev-C &#xff0c;提供轻量、免费、开源的C/CIDE。Dev-C是最适合初学C语言的IDE之一&#xff0c;但至2015年Dev C5.11&#xff0c;停止了更新维护了。 后来&…

springboot,vue电影院售票系统

开发工具&#xff1a;IDEA服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8项目构建&#xff1a;maven数据库&#xff1a;mysql5.7系统用户前台和管理后台两部分&#xff0c;项目采用前后端分离前端技术&#xff1a;vue elementUI服务端技术&#xff1a;springbootmybatis项目功…

pom文件中自定义的repository不生效

问题描述 对应的pom中依赖获取失败 pom文件依赖配置如下: <dependencies><dependency><groupId>it.geosolutions</groupId><artifactId>geoserver-manager</artifactId><version>1.7.0</version><exclusions><excl…