golang命令行选项解析插件库go-flags的使用

golang命令行选项解析插件库go-flags的使用

go-flags是一个用于解析命令行参数的Go语言库,它提供了比Go内置flag库更丰富的功能和更好的格式化支持。

主要特性

  • 支持短选项(-v)和长选项(–verbose)
  • 支持带参数和不带参数的选项
  • 支持可选参数和默认值
  • 支持多个选项组
  • 生成格式良好的帮助信息
  • 支持–后的剩余参数
  • 支持忽略未知选项
  • 支持多种参数指定方式(-I/usr/include, -I=/usr/include, -I /usr/include)
  • 支持组合短选项(-aux)
  • 支持所有Go基本类型
  • 支持多次指定同一选项(可存储为切片或只取最后一次)
  • 支持map类型
  • 支持回调函数
  • 支持命名空间(嵌套选项组)

使用示例

package main

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/jessevdk/go-flags"
)

// 定义选项结构体
type Options struct {
	// 布尔切片,每次遇到选项会追加true(可多次设置,如-vvv)
	Verbose []bool `short:"v" long:"verbose" description:"显示详细调试信息"`

	// 自动转换为uint类型
	Offset uint `long:"offset" description:"偏移量"`

	// 回调函数,每次找到选项时调用
	Call func(string) `short:"c" description:"拨打电话号码"`

	// 必填标志
	Name string `short:"n" long:"name" description:"名称" required:"true"`

	// 限制为预定义字符串集合的标志
	Animal string `long:"animal" choice:"cat" choice:"dog"`

	// 带值名称的选项
	File string `short:"f" long:"file" description:"文件" value-name:"FILE"`

	// 指针示例
	Ptr *int `short:"p" description:"整数指针"`

	// 字符串切片
	StringSlice []string `short:"s" description:"字符串切片"`

	// 指针切片
	PtrSlice []*string `long:"ptrslice" description:"字符串指针切片"`

	// map示例
	IntMap map[string]int `long:"intmap" description:"字符串到整数的映射"`

	// 环境变量示例
	Thresholds []int `long:"thresholds" default:"1" default:"2" env:"THRESHOLD_VALUES" env-delim:","`
}

func main() {
	var opts Options

	// 设置回调函数
	opts.Call = func(num string) {
		cmd := exec.Command("open", "callto:"+num)
		cmd.Start()
		cmd.Process.Release()
	}

	// 解析命令行参数
	_, err := flags.Parse(&opts)
	if err != nil {
		panic(err)
	}

	// 打印解析结果
	fmt.Printf("详细模式: %v\n", opts.Verbose)
	fmt.Printf("偏移量: %d\n", opts.Offset)
	fmt.Printf("名称: %s\n", opts.Name)
	if opts.Animal != "" {
		fmt.Printf("动物: %s\n", opts.Animal)
	}
	if opts.Ptr != nil {
		fmt.Printf("指针: %d\n", *opts.Ptr)
	}
	fmt.Printf("字符串切片: %v\n", opts.StringSlice)
	if len(opts.PtrSlice) > 0 {
		fmt.Printf("指针切片: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1])
	}
	if len(opts.IntMap) > 0 {
		fmt.Printf("整数映射: %v\n", opts.IntMap)
	}
}

更复杂的示例

package main

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/jessevdk/go-flags"
)

func main() {
	var opts struct {
		Verbose     []bool `short:"v" long:"verbose" description:"显示详细调试信息"`
		Offset      uint   `long:"offset" description:"偏移量"`
		Call        func(string) `short:"c" description:"拨打电话号码"`
		Name        string `short:"n" long:"name" description:"名称" required:"true"`
		Animal      string `long:"animal" choice:"cat" choice:"dog"`
		File        string `short:"f" long:"file" description:"文件" value-name:"FILE"`
		Ptr         *int   `short:"p" description:"整数指针"`
		StringSlice []string `short:"s" description:"字符串切片"`
		PtrSlice    []*string `long:"ptrslice" description:"字符串指针切片"`
		IntMap      map[string]int `long:"intmap" description:"字符串到整数的映射"`
	}

	opts.Call = func(num string) {
		cmd := exec.Command("open", "callto:"+num)
		cmd.Start()
		cmd.Process.Release()
	}

	// 模拟命令行参数
	args := []string{
		"-vv",
		"--offset=5",
		"-n", "Me",
		"--animal", "dog",
		"-p", "3",
		"-s", "hello",
		"-s", "world",
		"--ptrslice", "hello",
		"--ptrslice", "world",
		"--intmap", "a:1",
		"--intmap", "b:5",
		"arg1",
		"arg2",
		"arg3",
	}

	// 解析参数
	args, err := flags.ParseArgs(&opts, args)
	if err != nil {
		panic(err)
	}

	fmt.Printf("详细模式: %v\n", opts.Verbose)
	fmt.Printf("偏移量: %d\n", opts.Offset)
	fmt.Printf("名称: %s\n", opts.Name)
	fmt.Printf("动物: %s\n", opts.Animal)
	fmt.Printf("指针: %d\n", *opts.Ptr)
	fmt.Printf("字符串切片: %v\n", opts.StringSlice)
	fmt.Printf("指针切片: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1])
	fmt.Printf("整数映射: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"])
	fmt.Printf("剩余参数: %s\n", strings.Join(args, " "))
}

这个库通过结构体、反射和结构体字段标签来指定命令行选项,使得应用程序选项的指定变得非常简单和简洁。


更多关于golang命令行选项解析插件库go-flags的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang命令行选项解析插件库go-flags的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-flags 命令行选项解析库使用指南

go-flags 是一个功能强大的 Go 语言命令行选项解析库,它支持 POSIX/GNU 风格的命令行选项解析。下面我将详细介绍它的使用方法。

基本用法

首先安装 go-flags:

go get github.com/jessevdk/go-flags

1. 定义选项结构

package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"os"
)

type Options struct {
	Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
	Port    int    `short:"p" long:"port" description:"Port to listen on" default:"8080"`
	Config  string `short:"c" long:"config" description:"Config file path" required:"true"`
}

func main() {
	var opts Options
	parser := flags.NewParser(&opts, flags.Default)
	
	_, err := parser.Parse()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf("Options: %+v\n", opts)
}

2. 运行示例

$ go run main.go -c config.yaml -p 9090 -vvv
Options: {Verbose:[true true true] Port:9090 Config:config.yaml}

高级特性

1. 子命令支持

type GlobalOptions struct {
	Verbose bool `short:"v" long:"verbose" description:"Show verbose debug information"`
}

type StartCommand struct {
	Port int `short:"p" long:"port" description:"Port to listen on" default:"8080"`
}

type StopCommand struct {
	Force bool `short:"f" long:"force" description:"Force stop"`
}

func main() {
	var globalOpts GlobalOptions
	var startCmd StartCommand
	var stopCmd StopCommand

	parser := flags.NewParser(&globalOpts, flags.Default)
	parser.AddCommand("start", "Start the server", "", &startCmd)
	parser.AddCommand("stop", "Stop the server", "", &stopCmd)

	_, err := parser.Parse()
	if err != nil {
		os.Exit(1)
	}

	if parser.Active != nil {
		switch parser.Active.Name {
		case "start":
			fmt.Printf("Starting server on port %d (verbose: %v)\n", 
				startCmd.Port, globalOpts.Verbose)
		case "stop":
			fmt.Printf("Stopping server (force: %v, verbose: %v)\n", 
				stopCmd.Force, globalOpts.Verbose)
		}
	}
}

2. 自定义验证

type Options struct {
	Age int `short:"a" long:"age" description:"Your age" validate:"min=18,max=120"`
}

func main() {
	var opts Options
	parser := flags.NewParser(&opts, flags.Default)
	
	_, err := parser.Parse()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	
	fmt.Printf("Age: %d\n", opts.Age)
}

3. 环境变量支持

type Options struct {
	Debug bool `long:"debug" env:"APP_DEBUG" description:"Enable debug mode"`
}

func main() {
	var opts Options
	parser := flags.NewParser(&opts, flags.Default)
	
	_, err := parser.Parse()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	
	fmt.Printf("Debug mode: %v\n", opts.Debug)
}

4. 自定义处理函数

type Options struct {
	Files []string `short:"f" long:"file" description:"Files to process"`
}

func main() {
	var opts Options
	parser := flags.NewParser(&opts, flags.Default)
	
	parser.AddOption(&flags.Option{
		LongName:    "custom",
		Description: "Custom option",
		Required:    false,
		Handler: func(option *flags.Option) error {
			fmt.Println("Custom option handler called")
			return nil
		},
	})
	
	_, err := parser.Parse()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	
	fmt.Printf("Files: %v\n", opts.Files)
}

错误处理

go-flags 提供了多种错误处理方式:

func main() {
	var opts struct {
		Name string `short:"n" long:"name" required:"true"`
	}
	
	parser := flags.NewParser(&opts, flags.Default)
	
	_, err := parser.Parse()
	if flagsErr, ok := err.(*flags.Error); ok {
		switch flagsErr.Type {
		case flags.ErrHelp:
			// 用户请求帮助信息
			os.Exit(0)
		case flags.ErrRequired:
			fmt.Println("Required option missing:", flagsErr.Message)
		default:
			fmt.Println("Error:", flagsErr.Message)
		}
		os.Exit(1)
	} else if err != nil {
		fmt.Println("Unexpected error:", err)
		os.Exit(1)
	}
	
	fmt.Println("Name:", opts.Name)
}

总结

go-flags 是一个功能全面的命令行解析库,主要特点包括:

  • 支持短选项(-v)和长选项(–verbose)
  • 支持子命令
  • 支持默认值和必填选项
  • 支持环境变量
  • 支持自定义验证
  • 提供详细的帮助信息生成
  • 支持选项分组

通过结构体标签可以方便地定义选项的各种属性,使得代码既简洁又易于维护。

回到顶部