Go urfave/cli
最后修改时间 2024 年 4 月 11 日
在本文中,我们将展示如何使用 urfave/cli 包在 Golang 中创建命令行工具。
urfave/cli 是一个简单快速的包,用于在 Go 中构建命令行应用程序。它支持命令、子命令、标志、自动帮助系统、动态 shell 补全和 markdown 文档生成。
简单的 CLI 示例
下面的示例演示了如何创建一个简单的 CLI 应用程序骨架。
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "my cli application"
app.Action = (func(ctx *cli.Context) error {
fmt.Println("app launched")
return nil
})
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
该程序运行时会显示一条简短的消息。
import (
"fmt"
"log"
"os"
"github.com/urfave/cli"
)
导入了该包。
app := cli.NewApp()
使用 cli.NewApp 创建了一个新的 CLI 应用程序。它为应用程序设置了一些默认值。
app.Name = "my cli application"
我们通过 Name 字段为应用程序设置名称。
app.Action = (func(ctx *cli.Context) error {
fmt.Println("app launched")
return nil
})
Action 字段被设置为一个函数,当没有指定子命令时会调用该函数。
err := app.Run(os.Args)
Run 函数解析参数切片并将它们路由到正确的标志/参数组合。
$ go build $ simple.exe app launched
我们构建并运行该应用程序。
$ simple.exe -h NAME: my cli application - A new cli application USAGE: simple.exe [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
urfave/cli 会自动为我们的工具创建帮助信息。
CLI 参数
通过 Args 函数可以检索传递给程序的参数。
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Usage: "app a1 a2 ...",
Action: func(ctx *cli.Context) error {
n := ctx.NArg()
fmt.Printf("app received %d arguments\n", n)
if n >= 2 {
first := ctx.Args().First()
rest := ctx.Args().Tail()
fmt.Printf("first argument: %s\n", first)
fmt.Printf("the remaining arguments: %v\n", rest)
} else if n == 1 {
first := ctx.Args().First()
fmt.Printf("first argument: %s\n", first)
}
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
该程序检索传递的参数。
n := ctx.NArg()
fmt.Printf("app received %d arguments\n", n)
NArg 返回传递的命令行参数的数量。
first := ctx.Args().First() rest := ctx.Args().Tail()
First 函数返回第一个参数。Tail 返回其余参数(除第一个以外的所有参数)。
$ nargs.exe 1 2 3 4 app received 4 arguments first argument: 1 the remaining arguments: [2 3 4]
检查参数
使用 Present 函数,我们可以检查是否向程序传递了任何参数。
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Action: func(ctx *cli.Context) error {
if ctx.Args().Present() {
fmt.Println(ctx.App.Name)
fmt.Println(ctx.NArg())
fmt.Println(ctx.Args().First())
fmt.Println(ctx.Args().Tail())
} else {
fmt.Println("No arguments specified")
}
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
如果没有参数,应用程序将打印“未指定参数”消息。
$ checkargs.exe 1 2 3 4 checkargs.exe 4 1 [2 3 4] $ checkargs.exe No arguments specified
Get 函数
Get 函数返回第 n 个参数,否则返回一个空字符串。
package main
import (
"fmt"
"log"
"os"
"time"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Name: "app",
Usage: "app [now] [hello]",
Action: func(ctx *cli.Context) error {
a := ctx.Args().Get(0)
if a == "now" {
now := time.Now()
fmt.Println(now)
} else if a == "hello" {
fmt.Println("hello there!")
} else {
fmt.Printf("Usage: %s\n", ctx.App.Usage)
}
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
在程序中,我们检索第一个命令行参数,并根据参数是否等于“now”或“hello”来执行操作。
a := ctx.Args().Get(0)
我们使用 Get 检索第一个参数。在这种情况下,我们也可以使用 First。
if a == "now" {
now := time.Now()
fmt.Println(now)
} else if a == "hello" {
fmt.Println("hello there!")
} else {
fmt.Printf("Usage: %s\n", ctx.App.Usage)
}
如果参数等于“now”,我们打印当前日期时间。如果等于“hello”,我们打印一条消息。否则,将使用 ctx.App.Usage 打印用法。
$ app.exe now 2023-10-03 12:34:08.5846632 +0200 CEST m=+0.003355301 $ app.exe hello hello there!
CLI 命令
命令是工具执行的特定操作。前面的示例有两个命令:now 和 hello。现在我们重写程序以使用命令。
package main
import (
"fmt"
"log"
"os"
"time"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Name: "app",
Commands: []*cli.Command{
{
Name: "now",
Usage: "Show current local datetime",
Action: func(c *cli.Context) error {
now := time.Now()
fmt.Println(now)
return nil
},
},
{
Name: "hello",
Usage: "Show hello message",
Action: func(c *cli.Context) error {
fmt.Println("Hello there!")
return nil
},
},
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
命令在 Commands 字段中指定。
{
Name: "now",
Usage: "Show current local datetime",
Action: func(c *cli.Context) error {
now := time.Now()
fmt.Println(now)
return nil
},
},
我们为命令指定了 Name、Usage 和 Action。
CLI 标志
标志用于将值传递给命令行应用程序。
-count=x -count x --count=x --count x
有几种指定标志的方法。另请注意,布尔标志不需要值。
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{Name: "name"},
},
Action: func(ctx *cli.Context) error {
name := ctx.Value("name")
fmt.Println(name)
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
该程序接受一个 name 标志。
Flags: []cli.Flag{
&cli.StringFlag{Name: "name"},
},
标志通过 Flags 字段指定。name 标志是一个 StringFlag。
Action: func(ctx *cli.Context) error {
name := ctx.Value("name")
fmt.Println(name)
return nil
},
在 Action 函数中,我们使用 Value 获取标志的值。
$ flag.exe --name "John Doe" John Doe
别名
我们可以为我们的标志指定别名。别名是标志的另一个名称。
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{Name: "config", Aliases: []string{"cfg", "conf"}},
},
Action: func(ctx *cli.Context) error {
fmt.Println(ctx.String("config"))
fmt.Println(ctx.String("cfg"))
fmt.Println(ctx.String("conf"))
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
config 标志有 cfg 和 conf 别名。
Flags: []cli.Flag{
&cli.StringFlag{Name: "config", Aliases: []string{"cfg", "conf"}},
},
别名通过 Aliases 选项指定。
fmt.Println(ctx.String("config"))
fmt.Println(ctx.String("cfg"))
fmt.Println(ctx.String("conf"))
我们通过所有三个选项检索值。
$ aliases.exe -cfg file.txt file.txt file.txt file.txt
目标
Destination 选项可用于指定将要复制传递值变量。
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
var name string
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{Name: "name", Destination: &name},
},
Action: func(ctx *cli.Context) error {
msg := fmt.Sprintf("Hello %s!", name)
fmt.Println(msg)
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
在程序中,我们将 name 参数的值复制到 name 变量。
应用程序版本
应用程序版本可以通过 Version 和 VersionFlag 设置。
package main
import (
"os"
"github.com/urfave/cli/v2"
)
func main() {
cli.VersionFlag = &cli.BoolFlag{
Name: "version",
Aliases: []string{"V"},
Usage: "shows the app version",
}
app := &cli.App{
Name: "app",
Usage: "app demonstrating version",
Version: "v1.0",
}
app.Run(os.Args)
}
在示例中,我们设置了应用程序的版本。
cli.VersionFlag = &cli.BoolFlag{
Name: "version",
Aliases: []string{"V"},
Usage: "shows the app version",
}
我们指定了标志名称、别名和用法。使用了 BoolFlag。
app := &cli.App{
Name: "app",
Usage: "app demonstrating version",
Version: "v1.0",
}
我们指定了版本字符串。
$ app.exe --version app version v1.0
来源
在本文中,我们展示了如何使用 urfave/cli 包创建 Go 命令行工具。