一种命令行解析的新思路(Go 语言描述)
一 概述
二 现有的命令行解析方法
// demo.go
var limit int
flag.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 100
the limit is 100
package main
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
funcmain() {
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 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, " "))
}
},
}
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()
}
echotimes hello --times 3 go run cobra.go
Echo: hello
Echo: hello
Echo: hello
1 参数定义跟命令逻辑分离
// 为什么我不能写成下面这样呢?
functimes(){
cobra.IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
cobra.Parse()
}
2 子命令与父命令的顺序定义不够灵活
三 重新认识命令行
1 命令行只是一个可被 shell 解析执行的字符串
cmd arg1 arg2 arg3
2 参数、标识与选项
flag.IntVar(&limit, "limit", 10, "the max number of results")
// 变量绑定,当在命令行中指定 -limit 100 的时候,这意味着我们是把 100 这个值,赋予变量 limit
3 子命令
// 不带有横线的参数也可以实现关联变量或函数
for _, arg := range os.Args{
switch arg{
case"limit": // 设置 limit 变量
case"scan": // 调用 scan 函数
}
}
4 命令行的构成
标识(flag):以横线或双横线开头的参数,标识又由标识名和标识参数组成
--flagname flagarg
非标识参数
子命令(subcommand),子命令也会有子命令,标识和非标识参数
command --flag flagarg subcommand subcmdarg --subcmdfag subcmdflagarg
四 启发式命令行解析
funccommand(){
// 定义 flags
// 调用 Parse 函数
}
echotimes hello --times 3 app
1 简单解析流程
定义echo子命令关联到函数echo, echo times子命令关联到函数 echoTimes 解析字符串 echo times hello --times 3 解析第一个参数,通过 echo匹配到我们预定义的 echo子命令,同时发现这也是 echo times命令的前缀部分,此时,只有知道后一个参数是什么,我们才能确定用户调用的是 echo还是 echo times 解析第二个参数,通过 times我们匹配到 echo times子命令,并且其不再是任何子命令的前缀。此时确定子命令为 echo times,其他所有参数皆为这个子命令的参数。 如果解析第二个参数为 hello,那么其只能匹配到 echo这个子命令,那么会调用 echo函数而不是 echoTimes函数。
2 启发式探测流程
echo --color red times hello --times 3 app
解析到 red时,用 echo red搜索预定义的子命令,若搜索不到,则将 red视为参数 解析 times时,用 echo times搜索预定义的子命令,此时可搜索到 echo times子命令
3 子命令任意书写顺序
# 关联到 echoTimes 函数
"echo times" => echoTimes
# 调整子命令只是改一下这个映射而已
"times echo" => echoTimes
五 Cortana: 基于启发式命令行解析的实现
package main
import (
"fmt"
"strings"
"github.com/shafreeck/cortana"
)
funcprint() {
cortana.Title("Print anything to the screen")
cortana.Description(`print is for printing anything back to the screen.
For many years people have printed back to the screen.`)
args := struct {
Texts []string`cortana:"texts"`
}{}
cortana.Parse(&args)
fmt.Println(strings.Join(args.Texts, " "))
}
funcecho() {
cortana.Title("Echo anything to the screen")
cortana.Description(`echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`)
args := struct {
Texts []string`cortana:"texts"`
}{}
cortana.Parse(&args)
fmt.Println(strings.Join(args.Texts, " "))
}
funcechoTimes() {
cortana.Title("Echo anything to the screen more times")
cortana.Description(`echo things multiple times back to the user by providing
a count and a string.`)
args := struct {
Times int`cortana:"--times, -t, 1, times to echo the input"`
Texts []string`cortana:"texts"`
}{}
cortana.Parse(&args)
for i := 0; i < args.Times; i++ {
fmt.Println(strings.Join(args.Texts, " "))
}
}
funcmain() {
cortana.AddCommand("print", print, "print anything to the screen")
cortana.AddCommand("echo", echo, "echo anything to the screen")
cortana.AddCommand("echo times", echoTimes, "echo anything to the screen more times")
cortana.Launch()
}
# 不加任何子命令,输出自动生成的帮助信息
$ ./app
Available commands:
printprint anything to the screen
echoecho anything to the screen
echotimesecho anything to the screen more times
# 默认启用 -h, --help 选项,开发者无需做任何事情
$ ./app print -h
Print anything to the screen
print is for printing anything back to the screen.
For many years people have printed back to the screen.
Usage: print [texts...]
-h, --helphelpfor the command
# echo 任意内容
$ ./app echo hello world
hello world
# echo 任意次数
$ ./app echotimes hello world --times 3
hello world
hello world
hello world
# --times 参数可以在任意位置
$ ./app echo --times 3 times hello world
hello world
hello world
hello world
1 选项与默认值
args := struct {
Times int`cortana:"--times, -t, 1, times to echo the input"`
Texts []string`cortana:"texts"`
}{}
长标识名(long): --flagname, 任意标识都支持长标识名的格式,如果不写,则默认用字段名
短标识名(short): -f,可以省略
默认值(default):可以为任意跟字段类型匹配的值,如果省略,则默认为空值,如果为单个横线 "-",则标识用户必须提供一个值
描述(description):这个选项的描述信息,用于生成帮助信息,描述中可以包含任意可打印字符(包括逗号和空格)
2 子命令与别名
cortana.AddCommand("echo", echo, "echo anything to the screen")
// 定义 print 为 echo 命令的别名
cortana.Alias("print", "echo")
$ ./app print -h
Echo anything to the screen
echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
Available commands:
echotimesecho anything to the screen more times
Usage: echo [texts...]
-h, --helphelpfor the command
cortana.Alias("three", "echo times --times 3")
echotimes --times 3 的别名 three 是
./app three hello world
hello world
hello world
hello world
3 help 标识和命令
cortana.Use(cortana.HelpFlag("--usage", "-u"))
# 自定义 --usage 来打印帮助信息
$ ./app echo --usage
Echo anything to the screen
echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
Available commands:
echotimesecho anything to the screen more times
Usage: echo [texts...]
-u, --usage helpfor the command
cortana.Alias("help", "--help")
// 通过别名,实现 help 命令,用于打印任意子命令的帮助信息
$ ./app helpechotimes
Echo anything to the screen more times
echo things multiple times back to the user by providing
a count and a string.
Usage: echotimes [options] [texts...]
-t, --times <times> times to echo the input. (default=1)
-h, --helphelpfor the command
4 配置文件与环境变量
默认值 < 配置文件 < 环境变量 < 参数
cortana.AddConfig("app.json", cortana.UnmarshalFunc(json.Unmarshal))
5 没有子命令?
funcmain(){
args := struct {
Version bool`cortana:"--version, -v, , print the command version"`
}{}
cortana.Parse(&args)
if args.Version {
fmt.Println("v0.1.1")
return
}
// ...
}
./app --version
v0.1.1
六 总结
项目地址:https://github.com/shafreeck/cortana
数据库核心概念
数据库,简而言之可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据运行新增、截取、更新、删除等操作。数据库管理系统(Database Management System,简称DBMS)是为管理数据库而设计的电脑软件系统,一般具有存储、截取、安全保障、备份等基础功能 要想学习数据库,需要了解SQL、索引、视图、锁等概念,本节课带你走进数据库。
阅读原文 关键词
变量
字符串
命令行
程序
语言
最新评论
推荐文章
作者最新文章
你可能感兴趣的文章
Copyright Disclaimer: The copyright of contents (including texts, images, videos and audios) posted above belong to the User who shared or the third-party website which the User shared from. If you found your copyright have been infringed, please send a DMCA takedown notice to [email protected]. For more detail of the source, please click on the button "Read Original Post" below. For other communications, please send to [email protected].
版权声明:以上内容为用户推荐收藏至CareerEngine平台,其内容(含文字、图片、视频、音频等)及知识版权均属用户或用户转发自的第三方网站,如涉嫌侵权,请通知[email protected]进行信息删除。如需查看信息来源,请点击“查看原文”。如需洽谈其它事宜,请联系[email protected]。
版权声明:以上内容为用户推荐收藏至CareerEngine平台,其内容(含文字、图片、视频、音频等)及知识版权均属用户或用户转发自的第三方网站,如涉嫌侵权,请通知[email protected]进行信息删除。如需查看信息来源,请点击“查看原文”。如需洽谈其它事宜,请联系[email protected]。