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 命令行工具。