背景

学习Golang并尝试应用于实际工作中。

什么是cli

cli一个简单,快速且有趣的软件包,用于在Go中构建命令行应用程序。目的是使开发人员能够以表达方式编写快速且可分发的命令行应用程序。目前为V1*和V2*,这里学新不学旧。

安装

在未安装go-mode可以使用go get 进行安装

1
go get -v github.com/urfave/cli

安装go-mode后在包中引用,会自动安装相关库,demo如下

1
2
3
4
5
6
7
8
9
10
package main

import (
"os"
"github.com/urfave/cli/v2"
)

func main() {
(&cli.App{}).Run(os.Args)
}

结果如下:

1
2
3
4
5
6
7
8
9
10
11
NAME:
ncshell - A new cli application

USAGE:
ncshell [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 (default: false)

使用

cli自带help参数进行构建。在cli库中使用cli.App进行填充命令与参数,使用Run()进行运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"fmt"
"log"
"os"

"github.com/urfave/cli/v2"
)

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)
}
}

另一种,使用实例化进行屌用:

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
package main

import (
"fmt"
"log"
"os"
"runtime" // 用于记录系统调度之类的
"github.com/urfave/cli/v2"
)


func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) // 使用所有CPU运行,现在是默认开启了
}

func main() {
app := cli.NewApp() // 实例化
app.Name = "x-crack"
app.Action = func(c *cli.Context) error { // 执行命令
fmt.Println("hello world")
return nil
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

在目标Action中,通过cli.Context的相关方法我们可以获取传给命令行的参数信息:

  1. NArg() 返回参数个数
  2. Args() 返回cli.Args对象,调用其Get(i)获取位置i上的参数。
  3. IsSet(“xxxx”) 查询是否设置xxxxx选项(调用需要string进行转换)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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)) // 获取参数的位置,获取的参数
}
if c.IsSet("debug") {
fmt.Println("1111")
}
return nil
},
}

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

增加选项 Flags:

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"
"log"
"os"

"github.com/urfave/cli/v2"
)

func main() {
app := &cli.App{
Flags: []cli.Flag { // 增减参数
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Action: func(c *cli.Context) error {
name := "Nefertiti" // 设置mane参数
if c.NArg() > 0 { // 这里是按照无命令参数计算的,比如 --lang xxx 并不会计算在其中
name = c.Args().Get(0)
}
if c.String("lang") == "spanish" { // --lang spanish 对参数内容进行限制
fmt.Println("Hola", name)
} else {
fmt.Println("Hello", 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
31
32
33
34
35
	...
Flags: []cli.Flag{
boolFlag("debug, d", "debug mode"),
intFlag("timeout, t", 5, "timeout"),
intFlag("scan_num, n", 5000, "thread num"),
stringFlag("ip_list, i", "iplist.txt", "iplist"),
stringFlag("user_dict, u", "user.dic", "user dict"),
stringFlag("pass_dict, p", "pass.dic", "password dict"),
stringFlag("outfile, o", "x_crack.txt", "scan result file"),
}
...

func stringFlag(name, value, usage string) cli.StringFlag {
return cli.StringFlag{
Name: name, // 参数名字
Value: value, // 参数值(默认值)
Aliases: []string{"c"}, //简称
Usage: usage, // 参数介绍
}
}

func boolFlag(name, usage string) cli.BoolFlag {
return cli.BoolFlag{
Name: name,
Usage: usage,
}
}

func intFlag(name string, value int, usage string) cli.IntFlag {
return cli.IntFlag{
Name: name,
Value: value,
Usage: usage,
}
}

官方写的,更过flag参数的使用说明可以查看官方的文档

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
package main

import (
"log"
"os"
"fmt"

"github.com/urfave/cli/v2"
)

func main() {
var language string

app := &cli.App{
Flags: []cli.Flag {
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
Destination: &language,
},
},
Action: func(c *cli.Context) error {
name := "someone"
if c.NArg() > 0 {
name = c.Args().Get(0)
}
if language == "spanish" {
fmt.Println("Hola", name)
} else {
fmt.Println("Hello", name)
}
return nil
},
}

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

使用command来进行命令与子命令的调用:

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
package main

import (
"log"
"os"

"github.com/urfave/cli/v2"
)

func main() {
app := &cli.App{
Commands: []*cli.Command{
{
Name: "noop",
},
{
Name: "add",
Category: "template",
},
{
Name: "remove",
Category: "template",
},
},
}

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

退出程序运行(在app.Run()中运行后,使用os是无法进行退出的):

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
package main

import (
"log"
"os"

"github.com/urfave/cli/v2"
)

func main() {
app := &cli.App{
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "ginger-crouton",
Usage: "is it in the soup?",
},
},
Action: func(ctx *cli.Context) error {
if !ctx.Bool("ginger-crouton") {
return cli.Exit("Ginger croutons are not in the soup", 86)
}
return nil
},
}

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}

学习/参考

1
2