您现在的位置: 首页 > 网站导航收录 > 百科知识百科知识
(lnt是什么意思)-lolnt是什么意思
命令,参数,命令行(lnt是什么意思)-lolnt是什么意思
发布时间:2020-12-06加入收藏来源:互联网点击:
很多朋友想了解关于lnt是什么意思的一些资料信息,下面是小编整理的与lnt是什么意思相关的内容分享给大家,一起来看看吧。
一 概述命令行解析是几乎每个后端程序员都会用到的技术,但相比业务逻辑来说,这些细枝末节显得并不紧要,如果仅仅追求满足简单需求,命令行的处理会比较简单,任何一个后端程序员都可以信手拈来。Go 标准库提供了 flag 库以供大家使用。
然而,当我们稍微想让我们的命令行功能丰富一些,问题开始变得复杂起来,比如,我们要考虑如何处理可选项和必选项,对于可选项,如何设置其默认值,如何处理子命令,以及子命令的子命令,如何处理子命令的参数等等。
目前,Go 语言中使用最广泛功能最强大的命令行解析库是 cobra,但丰富的功能让 cobra 相比标准库的 flag 而言,变得异常复杂,为了减少使用的复杂度,cobra 甚至提供了代码生成的功能,可以自动生成命令行的骨架。然而,自动生成在节省了开发时间的同时,也让代码变得不够直观。
本文通过打破大家对命令行的固有印象,对命令行的概念解构后重新梳理,开发出一种功能强大但使用极为简单的命令行解析方法。这种方法支持任意多的子命令,支持可选和必选参数,对可选参数可提供默认值,支持配置文件,环境变量及命令行参数同时使用,配置文件,环境变量,命令行参数生效优先级依次提高,这种设计可以更符合 12 factor的原则。
二 现有的命令行解析方法Go 标准库 flag提供了非常简单的命令行解析方法,定义好命令行参数后,只需要调用 flag.Parse方法即可。
// demo.govar limit intflag.IntVar(&limit, "limit", 10, "the max number of results")flag.Parse()fmt.Println("the limit is", limit)// 执行结果$ go run demo.go the limit is 10$ go run demo.go -limit 100the limit is 100可以看到, flag 库使用非常简单,定要好命令行参数后,只需要调用 flag.Parse就可以实现参数的解析。在定义命令行参数时,可以指定默认值以及对这个参数的使用说明。
如果要处理子命令,flag 就无能为力了,这时候可以选择自己解析子命令,但更多的是直接使用 cobra 这个库。
这里用 cobra 官方给出的例子,演示一下这个库的使用方法
package mainimport ( "fmt" "strings" "github.com/spf13/cobra")func main() { var echoTimes int var cmdPrint = &cobra.Command{ Use: "print [string to print]", Short: "Print anything to the screen", Long: `print is for printing anything back to the screen.For many years people have printed back to the screen.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Print: " + strings.Join(args, " ")) }, } var cmdEcho = &cobra.Command{ Use: "echo [string to echo]", Short: "Echo anything to the screen", Long: `echo is for echoing anything back.Echo works a lot like print, except it has a child command.`, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Println("Echo: " + strings.Join(args, " ")) }, } 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 providinga 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, " ")) } }, } cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") var rootCmd = &cobra.Command{Use: "app"} rootCmd.AddCommand(cmdPrint, cmdEcho) cmdEcho.AddCommand(cmdTimes) rootCmd.Execute()}可以看到子命令的加入让代码变得稍微复杂,但逻辑仍然是清晰的,并且子命令和跟命令遵循相同的定义模板,子命令还可以定义自己子命令。
$ go run cobra.go echo times hello --times 3Echo: helloEcho: helloEcho: hellocobra 功能强大,逻辑清晰,因此得到大家广泛的认可,然而,这里却有两个问题让我无法满意,虽然问题不大,但时时萦怀于心,让人郁郁。
1 参数定义跟命令逻辑分离
从上面 --times的定义可以看到,参数的定义跟命令逻辑的定义(即这里的 Run)是分离的,当我们有大量子命令的时候,我们更倾向把命令的定义放到不同的文件甚至目录,这就会出现命令的定义是分散的,而所有命令的参数定义却集中在一起的情况。
当然,这个问题用 cobra 也很好解决,只要把参数定义从 main函数移动到 init函数,并将 init 函数分散到跟子命令的定义一起即可。比如子命令 times 定义在 times.go文件中,同时在文件中定义 init函数,函数中定义了 times 的参数。然而,这样导致当参数比较多时需要定义大量的全局变量,这对于追求代码清晰简洁无副作用的人来说如芒刺背。
为什么不能像 flag库一样,把参数定义放到命令函数的里面呢?这样代码更紧凑,逻辑更直观。
// 为什么我不能写成下面这样呢?func times(){ cobra.IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") cobra.Parse()}相信大家稍加思考就会明白,times函数只有解析完命令行参数才能调用,这就要求命令行参数要事先定义好,如果把参数定义放到 times,这就意味着只有调用 times函数时才会解析相关参数,这就跟让手机根据外壳颜色变换主题一样无理取闹,可是,真的是这样吗?
2 子命令与父命令的顺序定义不够灵活
在开发有子命令甚至多级子命令的工具时,我们经常面临到底是选择 cmd {resource} {action}还是 cmd {action} {resource}的问题,也就是 resource 和 action 谁是子命令谁是参数的问题,比如 Kubernetes 的设计,就是 action 作为子命令:kubectl get pods ... kubectl get deploy ...,而对于 action 因不同 resource 而差别很大时,则往往选择 resource 作为子命令, 比如阿里云的命令行工具: aliyun ecs ... aliyun ram ...
在实际开发过程中,一开始我们可能无法确定action 和 resource 哪个作为子命令会更好,在有多级子命令的情况下这个选择可能会更困难。
在不使用任何库的时候,开发者可能会选择在父命令中初始化相关资源,在子命令中执行代码逻辑,这样父命令和子命令相互调换变得非常困难。 这其实是一种错误的逻辑,调用子命令并不意味着一定要调用父命令,对于命令行工具来说,命令执行完进程就会退出,父命令初始化后的资源,并不会在子命令中重复使用。
cobra 的设计可以让大家规避这个错误逻辑,其子命令需要提供一个 Run 函数,在这个函数,应该实现初始化资源,执行业务逻辑,销毁资源的整个生命周期。然而,cobra 仍然需要定义父命令,即必须定义 echo 命令,才能定义 echo times 这个子命令。实际上,在很多场景下,父命令是没有执行逻辑的,特别是以 resource 作为父命令的场景,父命令的唯一作用就是打印这个命令的用法。
cobra 让子命令和父命令的定义非常简单,但父子调换仍然需要修改其间的链接关系,是否有方法让这个过程更简单一点呢?
三 重新认识命令行关于命令行的术语有很多,比如参数(argument),标识(flag)和选项(option)等,cobra 的设计是基于以下概念的定义Commands represent actions, Args are things and Flags are modifiers for those actions.
下一篇:返回列表
相关链接 |
||
网友回复(共有 0 条回复) |