golang标准命令行扩展支持子命令的插件库cmd的使用

golang标准命令行扩展支持子命令的插件库cmd的使用

cmd是一个极简库,可以轻松地使用标准flag库实现子命令功能。这个库扩展了标准库flag包,以支持子命令和更多功能,同时保持极简和惯用的API。

功能特性

  • 支持子命令
  • 自动bash补全
  • 标志值定义和检查
  • 显式位置参数定义
  • 自动生成使用说明文本

使用示例

基本子命令示例

package main

import (
	"fmt"
	"github.com/posener/cmd"
)

var (
	// 定义根命令,包含一个字符串标志
	root  = cmd.New()
	flag0 = root.String("flag0", "", "根命令字符串标志")

	// 从根命令定义第一个子命令,包含一个字符串标志
	sub1  = root.SubCommand("sub1", "第一个子命令")
	flag1 = sub1.String("flag1", "", "sub1字符串标志")

	// 从根命令定义第二个子命令,包含一个整型标志
	sub2  = root.SubCommand("sub2", "第二个子命令")
	flag2 = sub1.Int("flag2", 0, "sub2整型标志")
)

func main() {
	// 解析命令行参数
	root.ParseArgs("cmd", "sub1", "-flag1", "value")

	// 检查用户选择了哪个子命令
	switch {
	case sub1.Parsed():
		fmt.Printf("调用sub1,标志值: %s", *flag1)
	case sub2.Parsed():
		fmt.Printf("调用sub2,标志值: %d", *flag2)
	}
}

高级标志值验证示例

package main

import (
	"fmt"
	"github.com/posener/cmd"
	"github.com/posener/complete/v2/predict"
)

func main() {
	var (
		root = cmd.New()
		// 定义只接受'foo'和'bar'值的标志,并启用值检查
		flag1 = root.String("flag1", "", "第一个标志", predict.OptValues("foo", "bar"), predict.OptCheck())
		// 定义只接受Go文件路径的标志
		file = root.String("file", "", "文件路径", predict.OptPredictor(predict.Files("*.go")), predict.OptCheck())
		// 定义位置参数,可选值为'baz'和'buzz'但不强制检查
		args = root.Args("[args...]", "位置参数", predict.OptValues("baz", "buzz"))
	)

	// 解析模拟命令行参数
	root.ParseArgs("cmd", "-flag1", "foo", "-file", "cmd.go", "buz", "bazz")

	// 输出结果
	fmt.Println(*flag1, *file, *args)
}

位置参数处理示例

package main

import (
	"fmt"
	"github.com/posener/cmd"
)

func main() {
	var (
		root = cmd.New()
		// 定义位置参数变量
		args = root.Args("[args...]", "命令行位置参数")
	)

	// 解析模拟命令行参数
	root.ParseArgs("cmd", "v1", "v2", "v3")

	// 输出结果
	fmt.Println(*args)
}

自定义位置参数处理

package main

import (
	"fmt"
	"github.com/posener/cmd"
)

func main() {
	var (
		root = cmd.New()
		// 定义变量来保存位置参数
		src, dst string
	)

	// 定义自定义位置参数处理函数
	argsFn := cmd.ArgsFn(func(args []string) error {
		if len(args) != 2 {
			return fmt.Errorf("需要src和dst两个参数,但得到%d个参数", len(args))
		}
		src, dst = args[0], args[1]
		return nil
	})

	// 注册位置参数处理函数
	root.ArgsVar(argsFn, "[src] [dst]", "命令行位置参数")

	// 解析模拟命令行参数
	root.ParseArgs("cmd", "from.txt", "to.txt")

	// 输出结果
	fmt.Println(src, dst)
}

整数位置参数处理

package main

import (
	"fmt"
	"github.com/posener/cmd"
)

func main() {
	var (
		root = cmd.New()
		// 定义整数位置参数变量
		args cmd.ArgsInt
	)

	// 注册位置参数变量
	root.ArgsVar(&args, "[int...]", "要求和数字")

	// 解析模拟命令行参数
	root.ParseArgs("cmd", "10", "20", "30")

	// 计算并输出总和
	sum := 0
	for _, n := range args {
		sum += n
	}
	fmt.Println(sum)
}

固定数量位置参数处理

package main

import (
	"fmt"
	"github.com/posener/cmd"
)

func main() {
	var (
		root = cmd.New()
		// 定义固定2个位置参数的变量
		args = make(cmd.ArgsStr, 2)
	)

	// 注册位置参数变量
	root.ArgsVar(&args, "[src] [dst]", "命令行位置参数")

	// 解析模拟命令行参数
	root.ParseArgs("cmd", "from.txt", "to.txt")

	// 输出结果
	fmt.Println(args)
}

这些示例展示了如何使用cmd库创建支持子命令的命令行工具,包括标志定义、位置参数处理和各种验证功能。


更多关于golang标准命令行扩展支持子命令的插件库cmd的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang标准命令行扩展支持子命令的插件库cmd的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 标准命令行扩展:子命令插件库 cmd 使用指南

在 Go 语言中,标准库 flag 提供了基本的命令行参数解析功能,但对于复杂的命令行应用(特别是支持子命令的应用)来说可能不够灵活。cmd 并不是 Go 标准库的一部分,但我们可以使用标准库 flag 结合一些模式来实现子命令功能,或者使用第三方库如 cobraurfave/cli

使用标准库实现子命令

下面是一个使用标准库实现子命令的示例:

package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	// 定义顶级命令
	addCmd := flag.NewFlagSet("add", flag.ExitOnError)
	listCmd := flag.NewFlagSet("list", flag.ExitOnError)

	// 检查子命令
	if len(os.Args) < 2 {
		fmt.Println("expected 'add' or 'list' subcommands")
		os.Exit(1)
	}

	switch os.Args[1] {
	case "add":
		// 为 add 命令定义标志
		addName := addCmd.String("name", "", "Name to add")
		addAge := addCmd.Int("age", 0, "Age of the person")
		addCmd.Parse(os.Args[2:])
		fmt.Printf("Adding %s, age %d\n", *addName, *addAge)
	case "list":
		// 为 list 命令定义标志
		listAll := listCmd.Bool("all", false, "List all items")
		listCmd.Parse(os.Args[2:])
		if *listAll {
			fmt.Println("Listing all items")
		} else {
			fmt.Println("Listing recent items")
		}
	default:
		fmt.Println("expected 'add' or 'list' subcommands")
		os.Exit(1)
	}
}

使用第三方库 cobra

cobra 是一个流行的 Go 命令行库,广泛用于 Kubernetes、Docker 等知名项目。

安装 cobra

go get -u github.com/spf13/cobra/cobra

示例代码

package main

import (
	"fmt"
	"github.com/spf13/cobra"
	"os"
)

func main() {
	// 根命令
	var rootCmd = &cobra.Command{
		Use:   "myapp",
		Short: "My application is a demo for cobra",
		Long:  `A longer description of my application that spans multiple lines`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Hello from the root command")
		},
	}

	// 添加子命令
	var addCmd = &cobra.Command{
		Use:   "add",
		Short: "Add a new item",
		Long:  `Add a new item to the list`,
		Run: func(cmd *cobra.Command, args []string) {
			name, _ := cmd.Flags().GetString("name")
			age, _ := cmd.Flags().GetInt("age")
			fmt.Printf("Adding %s, age %d\n", name, age)
		},
	}

	// 为 add 命令添加标志
	addCmd.Flags().StringP("name", "n", "", "Name of the item")
	addCmd.Flags().IntP("age", "a", 0, "Age of the person")
	addCmd.MarkFlagRequired("name")

	// list 子命令
	var listCmd = &cobra.Command{
		Use:   "list",
		Short: "List all items",
		Run: func(cmd *cobra.Command, args []string) {
			all, _ := cmd.Flags().GetBool("all")
			if all {
				fmt.Println("Listing all items")
			} else {
				fmt.Println("Listing recent items")
			}
		},
	}

	listCmd.Flags().BoolP("all", "a", false, "List all items")

	// 将子命令添加到根命令
	rootCmd.AddCommand(addCmd, listCmd)

	// 执行命令
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

使用 urfave/cli 库

urfave/cli (原 codegangsta/cli) 是另一个流行的 Go 命令行库。

安装 cli

go get -u github.com/urfave/cli/v2

示例代码

package main

import (
	"fmt"
	"log"
	"os"

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

func main() {
	app := &cli.App{
		Name:  "myapp",
		Usage: "demonstrate subcommands",
		Commands: []*cli.Command{
			{
				Name:    "add",
				Aliases: []string{"a"},
				Usage:   "add a new item",
				Flags: []cli.Flag{
					&cli.StringFlag{
						Name:     "name",
						Aliases:  []string{"n"},
						Usage:    "name of the item",
						Required: true,
					},
					&cli.IntFlag{
						Name:    "age",
						Aliases: []string{"a"},
						Usage:   "age of the person",
						Value:   0,
					},
				},
				Action: func(c *cli.Context) error {
					fmt.Printf("Adding %s, age %d\n", c.String("name"), c.Int("age"))
					return nil
				},
			},
			{
				Name:    "list",
				Aliases: []string{"l"},
				Usage:   "list items",
				Flags: []cli.Flag{
					&cli.BoolFlag{
						Name:    "all",
						Aliases: []string{"a"},
						Usage:   "list all items",
						Value:   false,
					},
				},
				Action: func(c *cli.Context) error {
					if c.Bool("all") {
						fmt.Println("Listing all items")
					} else {
						fmt.Println("Listing recent items")
					}
					return nil
				},
			},
		},
	}

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

总结

  1. 标准库 flag:适合简单场景,需要手动处理子命令逻辑
  2. cobra:功能强大,适合复杂命令行应用,支持自动生成帮助文档、bash 补全等
  3. urfave/cli:API 简洁,适合快速开发中等复杂度的命令行应用

对于大多数项目,推荐使用 cobraurfave/cli,它们提供了更丰富的功能和更好的开发体验。

回到顶部