简介
cli
是一个用于构建命令行程序的库。我们之前也介绍过一个用于构建命令行程序的库cobra
。在功能上来说两者差不多,cobra
的优势是提供了一个脚手架,方便开发。cli
非常简洁,所有的初始化操作就是创建一个cli.App
结构的对象。通过为对象的字段赋值来添加相应的功能。
快速使用
安装cli
库,有v1
和v2
两个版本。如果没有特殊需求,一般安装v2
版本:
1
|
go get -u github.com/urfave/cli/v2
|
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import (
"fmt"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
app := &cli.App{
Name: "hello",
Usage: "hello world example",
Action: func(c *cli.Context)error {
fmt.Println("hello world")
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
使用非常简单,理论上创建一个cli.App
结构的对象,然后调用其Run()
方法,传入命令行的参数即可。一个空白的cli
应用程序如下:
1
2
3
|
func main(){
(&cli.App{}).Run(os.Args)
}
|
但是这个空白程序没有什么用处。我们的hello world
程序,设置了Name/Usage/Action
。Name
和Usage
都显示在帮助中,Action
是调用该命令行程序时实际执行的函数,需要的信息可以从参数cli.Context
获取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go
hello world
除了这个,cli为我们额外生成了帮助信息
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
hello - hello world example
USAGE:
[global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
|
参数
通过cli.Context
的相关方法我们可以获取传给命令行的参数信息:
NArg()
:返回参数个数;
Args()
:返回cli.Args
对象,调用其Get(i)
获取位置i
上的参数。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
app := &cli.App{
Name: "arguments",
Usage: "arguments example",
Action: func(c *cli.Context)error {
for i:=0;i<c.NArg();i++{
fmt.Printf("%d: %s\n",i+1,c.Args().Get(i))
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
输出
1
2
3
4
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go /bin/bash --c sss
1: /bin/bash
2: --c
3: sss
|
选项
一个好用的命令行程序怎么会少了选项呢?cli设置和获取选项非常简单。在cli.App{}结构初始化时,设置字段Flags即可添加选项。Flags字段是[]cli.Flag类型,cli.Flag实际上是接口类型。cli为常见类型都实现了对应的XxxFlag,如BoolFlag/DurationFlag/StringFlag等。它们有一些共用的字段,Name/Value/Usage(名称/默认值/释义)。看示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
func main(){
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Action: func(c *cli.Context)error {
for i:=0;i<c.NArg();i++{
fmt.Printf("%d: %s\n",i+1,c.Args().Get(i))
}
name := "world"
//获取flag lang的值
if c.String("lang") == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
默认调用
C:\Users\xx\Desktop\git\mydocker1>go run main.go
hello world
设置非英语
C:\Users\xx\Desktop\git\mydocker1>go run main.go -lang chinese
你好 world
C:\Users\xx\Desktop\git\mydocker1>go run main.go --lang chinese
你好 world
传入参数作为人名
C:\Users\xx\Desktop\git\mydocker1>go run main.go --lang chinese xx
你好 xx
通过--help查看帮助
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
flags - flag example
USAGE:
[global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--lang value language for the greeting (default: "english")
--help, -h show help
|
存入变量
除了通过c.Type(name)
来获取选项的值,我们还可以将选项存到某个预先定义好的变量中。只需要设置Destination
字段为变量的地址即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
func main(){
var language string
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
Destination: &language,
},
},
Action: func(c *cli.Context)error {
name := "world"
if c.NArg() > 0{
name = c.Args().Get(0)
}
//获取flag lang的值
if language == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
占位值
cli
可以在Usage
字段中为选项设置占位值,占位值通过反引号 ` 包围。只有第一个生效,其他的维持不变。占位值有助于生成易于理解的帮助信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
func main(){
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Usage: "Load configuration from `FILE`",
},
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
设置占位值之后,帮助信息中,该占位值会显示在对应的选项后面,对短选项也是有效的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
USAGE:
[global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--config FILE Load configuration from FILE
--help, -h show help
|
选项别名
选项可以设置多个别名,设置对应选项的Aliases
字段即可(如果是v1版本,直接在Name,可以以,
分隔设置多个值),例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
func main(){
var language string
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang",
Aliases: []string{"language","l"},
Value: "english",
Usage: "language for the greeting",
Destination: &language,
},
},
Action: func(c *cli.Context)error {
name := "world"
if c.NArg() > 0{
name = c.Args().Get(0)
}
//获取flag lang的值
if language == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
查看帮助信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
flags - flag example
USAGE:
[global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--lang value, --language value, -l value language for the greeting (default: "english")
--help, -h show help
使用--lang chinese、--language chinese和-l chinese效果是一样的。如果通过不同的名称指定同一个选项,会报错:
C:\Users\xx\Desktop\git\mydocker1>go run main.go --lang chinese xx
你好 xx
C:\Users\xx\Desktop\git\mydocker1>go run main.go --language chinese xx
你好 xx
C:\Users\xx\Desktop\git\mydocker1>go run main.go --l chinese xx
你好 xx
C:\Users\xx\Desktop\git\mydocker1>go run main.go --l chinese --lang xx
Cannot use two forms of the same flag: l lang
|
环境变量
除了通过执行程序时手动指定命令行选项,我们还可以读取指定的环境变量作为选项的值。只需要将环境变量的名字设置到选项对象的EnvVars
字段即可。可以指定多个环境变量名字,cli
会依次查找,第一个有值的环境变量会被使用。(v1版本只有EnvVar,可以以,
分隔设置多个值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
func main(){
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang,language,l",
Value: "english",
Usage: "language for the greeting",
EnvVars: []string{"APP_LANG","SYSTEM_LANG"},
},
},
Action: func(c *cli.Context)error {
name := "world"
if c.NArg() > 0{
name = c.Args().Get(0)
}
//获取flag lang的值
if c.String("lang") == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go
hello world
C:\Users\xx\Desktop\git\mydocker1>set APP_LANG=chinese
C:\Users\xx\Desktop\git\mydocker1>go run main.go
你好 world
C:\Users\xx\Desktop\git\mydocker1>go run main.go
hello world
C:\Users\xx\Desktop\git\mydocker1>set SYSTEM_LANG=chinese
C:\Users\xx\Desktop\git\mydocker1>go run main.go
你好 world
|
文件
cli
还支持从文件中读取选项的值,设置选项对象的FilePath
字段为文件路径:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
func main(){
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang,language,l",
Value: "english",
Usage: "language for the greeting",
FilePath: "./lang.txt",
},
},
Action: func(c *cli.Context)error {
name := "world"
if c.NArg() > 0{
name = c.Args().Get(0)
}
//获取flag lang的值
if c.String("lang") == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
在main.go
同级目录创建一个lang.txt
,输入内容chinese
。然后编译运行程序:
1
2
3
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go
你好 world
|
cli
还支持从YAML/JSON/TOML
等配置文件中读取选项值
有一个单独的包altsrc增加了对其他文件格式如(YAML/JSON/TOML)等配置文件获取标志值的支持
目前支持的输入源格式:
但开发人员可以通过实现altsrc来添加对其他输入源的支持。InputSourceContext用于指定源。
YAML示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
package main
import (
"fmt"
"github.com/urfave/cli/v2/altsrc"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
flags := []cli.Flag{
//yaml多级使用.分割
altsrc.NewStringFlag(&cli.StringFlag{Name: "test.lang",Aliases: []string{"lang"}}),
//指定加载的yaml配置文件路径
&cli.StringFlag{
Name: "load",
Usage: "load yaml `config` ",
},
}
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: flags,
//在执行命令前加载配置文件
Before: altsrc.InitInputSourceWithContext(flags,altsrc.NewYamlSourceFromFlagFunc("load")),
Action: func(c *cli.Context)error {
name := "world"
if c.NArg() > 0{
name = c.Args().Get(0)
}
//获取flag lang的值
if c.String("test.lang") == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
创建yaml load.yaml
1
2
3
|
test:
lang: english
|
运行
1
2
3
4
5
6
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go
你好 world
C:\Users\xx\Desktop\git\mydocker1>go run main.go --load load.yaml
hello world
|
JSON示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
package main
import (
"fmt"
"github.com/urfave/cli/v2/altsrc"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
flags := []cli.Flag{
//json多级使用.分割
altsrc.NewStringFlag(&cli.StringFlag{Name: "test.lang",Aliases: []string{"lang"}}),
//指定加载的json配置文件路径
&cli.StringFlag{
Name: "load",
Usage: "load json `config` ",
},
}
app := &cli.App{
Name: "flags",
Usage: "flag example",
Flags: flags,
//在执行命令前加载配置文件
Before: altsrc.InitInputSourceWithContext(flags,altsrc.NewJSONSourceFromFlagFunc("load")),
Action: func(c *cli.Context)error {
name := "world"
if c.NArg() > 0{
name = c.Args().Get(0)
}
//获取flag lang的值
if c.String("test.lang") == "english"{
fmt.Println("hello",name)
}else {
fmt.Println("你好",name)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
创建json文件 load1.json
1
2
3
4
5
|
{
"test": {
"lang": "english"
}
}
|
运行
1
2
3
4
5
6
7
8
9
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go
你好 world
C:\Users\xx\Desktop\git\mydocker1>go run main.go --load load1.json
hello world
C:\Users\xx\Desktop\git\mydocker1>go run main.go --lang chinese --load load1.json
你好 world
|
优先级
标志值源的优先级如下(从高到低):
- 用户指定的命令行选项值
- 环境变量(如果指定)
- 配置文件(如果指定)
- 默认定义在标志
组合短选项
我们时常会遇到有多个短选项的情况。例如 linux 命令ls -a -l
,可以简写为ls -al
。cli
也支持短选项合写,只需要设置cli.App
的UseShortOptionHandling
字段为true
即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
app := &cli.App{
UseShortOptionHandling: true,
Commands: []*cli.Command{
{
Name: "short",
Usage: "complete a task on the list",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "server",Aliases: []string{"s"}},
&cli.BoolFlag{Name: "option",Aliases: []string{"o"}},
&cli.BoolFlag{Name: "message",Aliases: []string{"m"}},
},
Action: func(c *cli.Context) error {
fmt.Println("server",c.Bool("server"))
fmt.Println("option",c.Bool("option"))
fmt.Println("message",c.Bool("message"))
return nil
},
},
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
运行
1
2
3
4
5
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go short -som ss
server true
option true
message true
|
需要特别注意一点,设置UseShortOptionHandling
为true
之后,我们不能再通过-
指定选项了,这样会产生歧义。例如-lang
,cli
不知道应该解释为l/a/n/g
4 个选项还是lang
1 个。--
还是有效的。
必要选项
如果将选项的Required
字段设置为true
,那么该选项就是必要选项。必要选项必须指定,否则会报错:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
Required: true,
},
},
Action: func(c *cli.Context) error {
if c.String("lang") == "english"{
fmt.Println("hello")
}else {
fmt.Println("你好")
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
不指定lang时
C:\Users\xx\Desktop\git\mydocker1>go run main.go
NAME:
main.exe - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--lang value language for the greeting (default: "english")
--help, -h show help (default: false)
2021/09/19 13:49:28 Required flag "lang" not set
指定lang
C:\Users\xx\Desktop\git\mydocker1>go run main.go --lang chinese
你好
|
帮助文档中的默认值
默认情况下,帮助文本中选项的默认值显示为Value
字段值。有些时候,Value
并不是实际的默认值。这时,我们可以通过DefaultText
设置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
app := &cli.App{
Flags: []cli.Flag{
&cli.IntFlag{
Name: "port",
Value: 0,
Usage: "Use a randomized port",
DefaultText: "random",
},
},
Action: func(c *cli.Context) error {
if c.String("lang") == "english"{
fmt.Println("hello")
}else {
fmt.Println("你好")
}
return nil
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
上面代码逻辑中,如果Value
设置为 0 就随机一个端口,这时帮助信息中default: 0
就容易产生误解了。通过DefaultText
可以避免这种情况:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
main.exe - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--port value Use a randomized port (default: random)
--help, -h show help (default: false)
|
子命令
子命令使命令行程序有更好的组织性。git有大量的命令,很多以某个命令下的子命令存在。例如git remote命令下有add/rename/remove等子命令,git submodule下有add/status/init/update等子命令。
cli通过设置cli.App的Commands字段添加命令,设置各个命令的SubCommands字段,即可添加子命令。非常方便!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main(){
app := &cli.App{
Commands: []*cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) error {
fmt.Println("added task:",c.Args().First())
return nil
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) error {
fmt.Println("completed task:",c.Args().First())
return nil
},
},
{
Name: "template",
Aliases: []string{"t"},
Usage: "option for task templates",
Subcommands: []*cli.Command{
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) error {
fmt.Println("new task template",c.Args().First())
return nil
},
},
{
Name: "remove",
Usage: "remove an existing template",
Action: func(c *cli.Context) error {
fmt.Println("remove task:",c.Args().First())
return nil
},
},
},
},
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
上面定义了 3 个命令add/complete/template
,template
命令定义了 2 个子命令add/remove
。编译、运行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
main.exe - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
COMMANDS:
add, a add a task to the list
complete, c complete a task on the list
template, t option for task templates
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help (default: false)
注意一点,子命令默认不显示在帮助信息中,需要显式调用子命令所属命令的帮助(./subcommand template --help):
C:\Users\xx\Desktop\git\mydocker1>go run main.go t --help
NAME:
main.exe template - option for task templates
USAGE:
main.exe template command [command options] [arguments...]
COMMANDS:
add add a new template
remove remove an existing template
help, h Shows a list of commands or help for one command
OPTIONS:
--help, -h show help (default: false)
C:\Users\xx\Desktop\git\mydocker1>go run main.go add dating
added task: dating
C:\Users\xx\Desktop\git\mydocker1>go run main.go complete dating
completed task: dating
C:\Users\xx\Desktop\git\mydocker1>go run main.go template add dating
new task template dating
C:\Users\xx\Desktop\git\mydocker1>go run main.go template remove dating
remove task: dating
|
分类
在子命令数量很多的时候,可以设置Category
字段为它们分类,在帮助信息中会将相同分类的命令放在一起展示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
func main(){
app := &cli.App{
Commands: []*cli.Command{
{
Name: "noop",
Usage: "Usage for noop",
},
{
Name: "add",
Category: "template",
Usage: "Usage for add",
},
{
Name: "remove",
Category: "template",
Usage: "Usage for remove",
},
},
}
err := app.Run(os.Args)
if err != nil{
log.Fatal(err)
}
}
|
运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
main.exe - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
COMMANDS:
noop Usage for noop
help, h Shows a list of commands or help for one command
template:
add Usage for add
remove Usage for remove
GLOBAL OPTIONS:
--help, -h show help (default: false)
|
自定义帮助信息
在cli中所有的帮助信息文本都可以自定义,整个应用的帮助信息模板通过AppHelpTemplate指定。命令的帮助信息模板通过CommandHelpTemplate设置,子命令的帮助信息模板通过SubcommandHelpTemplate设置。甚至可以通过覆盖cli.HelpPrinter这个函数自己实现帮助信息输出。下面程序在默认的帮助信息后添加个人网站和微信信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package main
import (
"fmt"
"github.com/urfave/cli"
"os"
)
func main(){
cli.AppHelpTemplate = fmt.Sprintf(`%s
WEBSITE: https://www.xieys.club
WECHAT: 赶路人`,cli.AppHelpTemplate)
(&cli.App{}).Run(os.Args)
}
|
运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
USAGE:
[global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
WEBSITE: https://www.xieys.club
WECHAT: 赶路人
|
改写帮助模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
package main
import (
"github.com/urfave/cli"
"os"
)
func main(){
cli.AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{ if len .Authors}}
AUTHOR:
{{range .Authors}}{{.}}{{end}}{{end}}{{if .Commands}}
COMMANDS:
{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
GLOBAL OPTIONS:
{{range .VisibleFlags}}{{.}}{{end}}{{end}}{{if .Copyright}}
COPYRIGHT:
{{.Copyright}}{{end}}{{if .Version}}
VERSION:
{{.Version}}{{end}}
`
app := &cli.App{
Name: "help",
Usage: "a new cli application",
Authors: []cli.Author{
{
Name: "xieys",
Email: "xieys_1993l@163.com",
},
},
}
app.Run(os.Args)
}
|
{{.XXX}}
其中XXX
对应cli.App{}
结构中设置的字段,例如上面Authors
:
运行
1
2
3
4
5
6
7
8
9
10
11
12
13
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
help - a new cli application
USAGE:
[global options] command [command options] [arguments...]
AUTHOR:
xieys <xieys_1993l@163.com>
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
|
通过覆盖HelpPrinter,只输出自己定制的信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package main
import (
"fmt"
"github.com/urfave/cli"
"io"
"os"
)
func main(){
cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
fmt.Println("Simple Help!")
}
(&cli.App{}).Run(os.Args)
}
|
运行
1
2
3
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
Simple Help!
|
内置选项
帮助选项
默认情况下,帮助选项为--help/-h
。我们可以通过cli.HelpFlag
字段设置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package main
import (
"github.com/urfave/cli/v2"
"os"
)
func main(){
cli.HelpFlag = &cli.BoolFlag{
Name: "heeeelp",
Aliases: []string{"haap"},
Usage: "help",
}
(&cli.App{}).Run(os.Args)
}
|
查看帮助
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
Incorrect Usage. flag: help requested
NAME:
main.exe - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--heeeelp, --haap help (default: false)
C:\Users\xx\Desktop\git\mydocker1>go run main.go --haap
NAME:
main.exe - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--heeeelp, --haap help (default: false)
|
版本选项
默认版本选项-v/--version
输出应用的版本信息。我们可以通过cli.VersionFlag
设置版本选项 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package main
import (
"github.com/urfave/cli/v2"
"os"
)
func main(){
cli.VersionFlag = &cli.BoolFlag{
Name: "print-version",
Aliases: []string{"V"},
Usage: "print only the version",
}
(&cli.App{
Name: "version",
Version: "V1.0.0",
}).Run(os.Args)
}
|
运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go --print-version
version version V1.0.0
C:\Users\xx\Desktop\git\mydocker1>go run main.go --help
NAME:
version - A new cli application
USAGE:
main.exe [global options] command [command options] [arguments...]
VERSION:
V1.0.0
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help (default: false)
--print-version, -V print only the version (default: false)
C:\Users\xx\Desktop\git\mydocker1>go run main.go -V
version version V1.0.0
|
还可以通过设置cli.VersionPrinter字段控制版本信息的输出内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"os"
)
func main(){
cli.VersionPrinter = func(c *cli.Context) {
fmt.Printf("version = %s reversion=1",c.App.Version)
}
cli.VersionFlag = &cli.BoolFlag{
Name: "print-version",
Aliases: []string{"V"},
Usage: "print only the version",
}
(&cli.App{
Name: "version",
Version: "V1.0.0",
}).Run(os.Args)
}
|
运行
1
2
3
|
C:\Users\xx\Desktop\git\mydocker1>go run main.go -V
version = V1.0.0 reversion=1
|
除此之外,cli还支持bash自动补全功能,参考