Go语言命令行参数及cobra使用教程

Go语言命令行参数及cobra使用教程

  • 1.原生命令行参数
  • 2.使用CIL框架Cobra
    • 创建 rootCmd
    • 创建你的 main.go
    • 创建其他命令
    • 子命令
    • 返回和处理错误
  • 3.cobra使用标志
  • 4.Cobra位置参数和自定义参数
  • 5.Cobra PreRun和PostRun钩子

1.原生命令行参数

os 包以跨平台的方式,提供了一些与操作系统交互的函数和变量。程序的命令行参数可从 os 包的 Args 变量获取;os 包外部使用 os.Args 访问该变量

os.Args 变量是一个字符串(string)的 切片(slice),os.Args 的第一个元素:os.Args[0],是命令本身的名字;其它的元素则是程序启动时传给它的参数

func main() {var s, sep stringfor i := 1; i < len(os.Args); i++ {s += sep + os.Args[i]sep = " "}fmt.Println(s)
}

执行程序,会输出所有参数,以空格做分割:

go run hello.go 1 2.1 nma

在这里插入图片描述


2.使用CIL框架Cobra

cobra

Cobra 应用程序将遵循以下组织结构:

▾ appName/▾ cmd/add.goyour.gocommands.gohere.gomain.go

创建 rootCmd

Cobra 不需要任何特殊的构造函数。只需创建命令即可

package cmdimport ("fmt""os""github.com/spf13/cobra""github.com/spf13/viper"
)var (cfgFile     string // 配置文件路径userLicense string // 许可证类型rootCmd = &cobra.Command{// 应用名称Use: "cobra-cli",// 应用简短描述Short: "A generator for Cobra based Applications",// 应用详细描述Long: `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.`,}
)// Execute 用于执行根命令 rootCmd
func Execute() error {return rootCmd.Execute()
}func init() {// 在执行任何子命令之前调用 initConfig() 函数cobra.OnInitialize(initConfig)// 配置文件rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")// 作者信息rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")// 许可证信息rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")// 使用Viper进行配置rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")// 将命令行标志绑定到 Viper 配置库中的相应参数err := viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))if err != nil {return}err2 := viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))if err2 != nil {return}// 设置默认配置值viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")viper.SetDefault("license", "apache")// 用于添加子命令rootCmd.AddCommand(addCmd)rootCmd.AddCommand(initCmd)
}// 初始化应用程序的配置
func initConfig() {// 判断是否指定了配置文件路径,如果指定了,则将其设置为 Viper 配置文件if cfgFile != "" {viper.SetConfigFile(cfgFile)} else {// 如果没有指定配置文件路径,就根据用户的主目录动态生成配置文件路径home, err := os.UserHomeDir()cobra.CheckErr(err)viper.AddConfigPath(home)viper.SetConfigType("yaml")viper.SetConfigName(".cobra")}// 用于自动读取环境变量viper.AutomaticEnv()// 用于读取配置文件。如果成功读取,则输出使用的配置文件路径if err := viper.ReadInConfig(); err == nil {fmt.Println("Using config file:", viper.ConfigFileUsed())}
}

创建你的 main.go

main.go 文件通常非常裸露。它有一个目的:初始化 Cobra:

package go_testimport "go-test/cmd"func main() {err := cmd.Execute()if err != nil {return}
}

创建其他命令

可以定义其他命令,并且通常每个命令都有自己的文件 在 cmd/ 目录中。

例如:如果要创建版本命令,则需要创建 cmd/version.go 和 使用以下内容填充它:

package cmdimport ("fmt""github.com/spf13/cobra"
)// 将 versionCmd 命令添加到根命令 rootCmd 中
func init() {rootCmd.AddCommand(versionCmd)
}var versionCmd = &cobra.Command{Use:   "version",Short: "Print the version number of Hugo",Long:  `All software has versions. This is Hugo's`,// 用于定义命令被执行时的具体操作// 在本例中,当执行 version 命令时,会打印出 “Hugo Static Site Generator v0.9 – HEAD” 版本信息Run: func(cmd *cobra.Command, args []string) {fmt.Println("Hugo Static Site Generator v0.9 -- HEAD")},
}

结合上面的代码,当用户输入 cobra-cli version 时,将会触发 versionCmd 命令的执行,打印出应用程序的版本信息

子命令

命令可能具有子命令,而子命令又可能具有其他子命令

请考虑以下目录结构:AddCommand

├── cmd
│   ├── root.go
│   └── sub1
│       ├── sub1.go
│       └── sub2
│           ├── leafA.go
│           ├── leafB.go
│           └── sub2.go
└── main.go

返回和处理错误

如果您希望向命令的调用方返回错误,可以使用RunE

package cmdimport ("fmt""github.com/spf13/cobra"
)func init() {rootCmd.AddCommand(tryCmd)
}var tryCmd = &cobra.Command{Use:   "try",Short: "Try and possibly fail at something",RunE: func(cmd *cobra.Command, args []string) error {if err := someFunc(); err != nil {return err}return nil},
}

3.cobra使用标志

标志提供修饰符来控制操作命令的运行方式

1、持久性标志

标志可以是“持久性的”,这意味着此标志将可用于它所分配的命令以及该命令下的每个命令。为全局标志,将标志指定为根上的持久标志

持久性标记的定义通常包括全局性的配置参数,例如日志级别、配置文件路径、全局选项等

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

2、本地标志

在本地分配标志,该标志仅适用于该特定命令

本地标记通常用于定义特定命令所需的选项和参数,例如某个命令的特定配置选项

localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")

3、使用 Config 绑定标志

可以使用 viper 绑定您的标志:

var author stringfunc init() {rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
}

使用 Viper 绑定命令行标志可使配置管理更加一致、灵活和可组合。然而,具体是否需要绑定命令行标志取决于你的应用程序需求和偏好,如果你认为手动处理命令行标志更适合你,也可以不使用 Viper 进行绑定

4、参数必须

默认情况下,标志是可选的,如果想设置某个参数是必要的,可以进行设置:

rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkFlagRequired("region")

或者,对于持久性标志:

rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkPersistentFlagRequired("region")

5、标记Groups

如果您有不同的标志必须一起提供(例如,如果他们提供标志,他们也必须提供标志),也可以强制进行设定:

rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
rootCmd.MarkFlagsRequiredTogether("username", "password")

还可以设置不同标记的互斥(也就是不能同时出现):

rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")

如果要要求组中至少有一个标志存在,也可以指定:

rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
rootCmd.MarkFlagsOneRequired("json", "yaml")
rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")

4.Cobra位置参数和自定义参数

可以指定位置参数的验证:

内置了以下验证器:Args Command

参数数量:

  • NoArgs- 如果有任何位置参数,则报告错误。
  • ArbitraryArgs- 接受任意数量的参数。
  • MinimumNArgs(int)- 如果提供的位置参数少于 N 个,则报告错误。
  • MaximumNArgs(int)- 如果提供了超过 N 个位置参数,则报告错误。
  • ExactArgs(int)- 如果位置参数不完全是 N 个,则报告错误。
  • RangeArgs(min, max)- 如果参数数不在min和max之间,则报告错误

论据内容:

  • OnlyValidArgs- 如果字段中未指定任何位置参数,则报告错误

此外,还可以将现有检查与任意其他检查相结合,例如:

var cmd = &cobra.Command{Short: "hello",Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),Run: func(cmd *cobra.Command, args []string) {fmt.Println("Hello, World!")},
}

可以设置任何满足的自定义验证器,例如:

var cmd = &cobra.Command{Short: "hello",Args: func(cmd *cobra.Command, args []string) error {if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {return err}// 运行自定义验证逻辑if myapp.IsValidColor(args[0]) {return nil}return fmt.Errorf("invalid color specified: %s", args[0])},Run: func(cmd *cobra.Command, args []string) {fmt.Println("Hello, World!")},
}

5.Cobra PreRun和PostRun钩子

在 Cobra 库中,命令的执行过程被分为多个阶段,并且 Cobra 提供了一些Hooks来允许开发者在这些阶段插入自定义的行为

1、PersistentPreRun

在执行任何命令之前调用 PersistentPreRun。可以使用这个钩子来进行全局的初始化操作或者检查全局的配置参数

2、PreRun

在执行该命令之前调用 PreRun。可以使用这个钩子来执行一些与特定命令相关的操作或配置检查

3、Run

当命令被执行时,会调用 Run 函数来执行实际的命令操作

4、PostRun

在执行完该命令之后调用 PostRun。可以使用这个钩子来执行一些与特定命令相关的清理工作或后处理操作

5、PersistentPostRun

在执行完任何命令之后调用 PersistentPostRun。可以使用这个钩子来进行全局的清理工作或输出全局概要信息

例如:

package mainimport ("fmt""github.com/spf13/cobra"
)func main() {var rootCmd = &cobra.Command{Use:   "root [sub]",Short: "My root command",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("Inside rootCmd Run 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)},}var subCmd = &cobra.Command{Use:   "sub [no options!]",Short: "My subcommand",PreRun: func(cmd *cobra.Command, args []string) {fmt.Printf("Inside subCmd PreRun with args: %v\n", args)},Run: func(cmd *cobra.Command, args []string) {fmt.Printf("Inside subCmd Run with args: %v\n", args)},PostRun: func(cmd *cobra.Command, args []string) {fmt.Printf("Inside subCmd PostRun with args: %v\n", args)},PersistentPostRun: func(cmd *cobra.Command, args []string) {fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)},}rootCmd.AddCommand(subCmd)rootCmd.SetArgs([]string{""})rootCmd.Execute()fmt.Println()rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})rootCmd.Execute()
}

输出:

Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
Inside rootCmd Run with args: []
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []Inside rootCmd PersistentPreRun with args: [arg1 arg2]
Inside subCmd PreRun with args: [arg1 arg2]
Inside subCmd Run with args: [arg1 arg2]
Inside subCmd PostRun with args: [arg1 arg2]
Inside subCmd PersistentPostRun with args: [arg1 arg2]

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

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

相关文章

Spring Boot 整合 MinIO自建对象存储服务

GitHub 地址&#xff1a;GitHub - minio/minio: The Object Store for AI Data Infrastructure 另外&#xff0c;MinIO 可以用来作为云原生应用的主要存储服务&#xff0c;因为云原生应用往往需要更高的吞吐量和更低的延迟&#xff0c;而这些都是 MinIO 的优势。安装过程跳过。…

CSS Grid 和 Flexbox

1.使用示例 CSS Grid&#xff1a; CSS Grid 是一种二维网格布局系统&#xff0c;可以用于创建复杂的网格布局。它允许你将元素放置到网格的行和列上&#xff0c;并通过设置网格属性来控制元素的位置和大小。 创建一个简单的 CSS Grid 布局&#xff0c;可以按照以下步骤进行&a…

Numpy基础

目录&#xff1a; 一、简介:二、array数组ndarray&#xff1a;1.array( )创建数组&#xff1a;2.数组赋值和引用的区别&#xff1a;3.arange( )创建区间数组&#xff1a;4.linspace( )创建等差数列&#xff1a;5.logspace( )创建等比数列&#xff1a;6.zeros( )创建全0数组&…

半导体设备系列:半导体制造产能扩张,设备零部件需求旺盛

近年来国内半导体制造产能不断扩张&#xff0c;半导体设备厂商加速成长。我们认为下游发展将拉动上游本地化配套需求&#xff0c;半导体设备零部件迎来高增长阶段。 摘要 半导体设备零部件包含密封圈、EFEM、射频电源、静电吸盘、硅电极、真空泵、气体流量计、喷淋头等产品&a…

python数据分析之交叉验证

python数据分析之交叉验证 1、常用的分类算法 有监督:SVM向量机、梯度提升、决策树(随机森林)、朴素贝叶斯、逻辑斯蒂回归、神经网络(cnn、rnn) 无监督:k-means、隐马尔可夫 2、数据分析过程 1、采集数据 2、数据预处理 3、特征选择 4、模型训练、评估、保存 5、模型…

JVM虚拟机:各种JVM报错总结

错误 java.lang.StackOverflowError java.lang.OutOfMemoryError:java heap space java.lang.OutOfMemoryError:GC overhead limit exceeded java.lang.OutOfMemoryError:Direct buffer memory java.lang.OutOfMemoryError:unable to create new native thread java.lang.OutOf…

时间计算总结

文章目录 1.1&#xff1a;Java 获取两个时间的时间差(时、分、秒)&#xff1a;依赖&#xff1a;方法的说明方法测试 2.1 获取当天的开始时间2.2 获取当天的结束时间2.3 获取昨天的开始时间2.4 获取昨天的结束时间2.5 获取明天的开始时间2.6 获取明天的结束时间2.7 获取本周的开…

第3章 【课后习题】(完整版)

【3.18】写出下面程序的运行结果 //3.18写出下面程序的运行结果 #include <iostream> using namespace std; class test{public:test();~test() {};private:int i; }; test::test() {i25;for(int ctr0;ctr<10;ctr){cout<<"Counting at "<<ctr…

深入浅出:理解 JavaScript 中的 Promise.all()

在现代的 JavaScript 开发中&#xff0c;异步编程是一个无法避免的话题。无论是处理网络请求&#xff0c;用户输入&#xff0c;还是文件操作&#xff0c;异步编程都扮演着核心角色。ES6 引入的 Promise 极大地简化了异步操作&#xff0c;而 Promise.all() 则为处理多个并行的异…

线程的深入学习(二)

前言 上一篇讲了线程池的相关知识&#xff0c;这篇文章主要讲解一个 1.并发工具类如CountDownLatch、CyclicBarrier等。 2.线程安全和并发集合&#xff1a; 3.学习如何使用Java提供的线程安全的集合类&#xff0c;如ConcurrentHashMap、CopyOnWriteArrayList等。 并发工具类 …

Linux学习记录——삼십삼 http协议

文章目录 1、URL2、http协议的宏观构成3、详细理解http协议1、http请求2、http响应1、有效载荷格式2、有效载荷长度3、客户端要访问的资源类型4、修改响应写法5、处理不同的请求6、跳转 3、请求方法&#xff08;GET/POST&#xff09;4、HTTP状态码&#xff08;实现3和4开头的&a…

uniapp中用户登录数据的存储方法探究

Hello大家好&#xff01;我是咕噜铁蛋&#xff01;作为一个博主&#xff0c;我们经常需要在应用程序中实现用户登录功能&#xff0c;并且需要将用户的登录数据进行存储&#xff0c;以便在多次使用应用程序时能够方便地获取用户信息。铁蛋通过科技手段帮大家收集整理了些知识&am…

每天五分钟计算机视觉:揭秘迁移学习

本文重点 随着人工智能的迅速发展,深度学习已经成为了许多领域的关键技术。然而,深度学习模型的训练需要大量的标注数据,这在很多情况下是不现实的。迁移学习作为一种有效的方法,可以在已有的数据和模型上进行训练,然后将其应用于新的任务。这种方法大大降低了对新任务的…

嵌入式(一)嵌入式系统介绍 | 嵌入式微处理器,嵌入式系统开发流程,嵌入式系统应用

文章目录 1 嵌入式系统基本介绍1.1 基本概念1.2 嵌入式微处理器分类1.2.1 微控制器MCU1.2.2 微处理器MPU1.2.3 数字信号处理器&#xff08;DSP&#xff09;1.2.4 混合处理器和片上系统&#xff08;SOC&#xff09;1.2.5 可编程片上系统&#xff08;SOPC&#xff09; 1.3 嵌入式…

书香之家 国学启智——学夫堂幼儿国学托管永嘉上塘实验店启航

在教育创新的道路上&#xff0c;学夫堂幼儿国学托管永嘉上塘实验店迎来了一个重要的时刻。经过三个多月的精心筹备和试运营&#xff0c;今天正式宣布学夫堂幼儿国学托管在永嘉县城北街道景和佳苑8幢105号开门迎客。 学夫堂深信&#xff0c;国学智慧不仅是中华文化的瑰宝&#x…

7-34 通讯录的录入与显示 分数 10

文章目录 每日一言题目输入格式&#xff1a;输出格式&#xff1a;输入样例&#xff1a;输出样例&#xff1a; 结语 每日一言 批判的武器当然不能代替武器的批判。 --〈黑格尔法哲学批判〉导言 题目 通讯录中的一条记录包含下述基本信息&#xff1a;朋友的姓名、出生日期、性别…

C++ const 限定符的全面介绍

C const 限定符的全面介绍 1. const 修饰基本数据类型 定义 const 修饰的基本数据类型变量&#xff0c;值不可改变。 语法 const type variable value;特点 不可变性&#xff0c;增加代码可读性。 作用 定义不可修改的常量。 使用场景 全局常量、配置项。 注意事项…

常见函数的4种类型(js的问题)

• 匿名函数 • 回调函数 • 递归函数 • 构造函数 1、匿名函数 定义时候没有任何变量引用的函数 匿名函数自调&#xff1a;函数只执行一次 (function(a, b){console.log(a b);} )(1, 2);// 等价于 function foo (a, b){console.log(a b); }foo(1, …

阿赵UE学习笔记——7、导入资源

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的使用。这次将会把一个带动作和贴图的钢铁侠模型&#xff0c;导入的UE的项目中。 1、准备的资源 这里有2个fbx文件&#xff0c;都是带着网格和动画的&#xff0c;模型网格和骨骼是一样的&#xff0c;只…

MySQL是如何做到可以恢复到半个月内任意一秒的状态的?

MySQL的逻辑架构图 MySQL中两个重要的日志模块&#xff1a;redo log&#xff08;重做日志&#xff09;和binlog&#xff08;归档日志&#xff09; 我们先来看redo log&#xff1a; 介绍一个MySQL里经常说到的WAL技术&#xff0c;即Write-Ahead-Logging&#xff0c;它的关键点…