Project Icon

go-arg

Go 语言结构体驱动的命令行参数解析库

go-arg 是一个基于结构体的 Go 语言命令行参数解析库。开发者可通过定义结构体来声明程序的命令行参数,支持必需参数、位置参数、环境变量和默认值等功能。该库还提供自定义验证、版本字符串和子命令等特性,适用于构建简单到复杂的命令行接口。go-arg 设计简洁,易于集成,适合各种规模的 Go 项目使用。

go-arg
go-arg

基于结构体的Go语言参数解析

Sourcegraph 文档 构建状态 覆盖率状态 Go报告卡


通过定义结构体来声明程序的命令行参数。

var args struct {
	Foo string
	Bar bool
}
arg.MustParse(&args)
fmt.Println(args.Foo, args.Bar)
$ ./example --foo=hello --bar
hello true

安装

go get github.com/alexflint/go-arg

必需参数

var args struct {
	ID      int `arg:"required"`
	Timeout time.Duration
}
arg.MustParse(&args)
$ ./example
用法: example --id ID [--timeout TIMEOUT]
错误: --id 是必需的

位置参数

var args struct {
	Input   string   `arg:"positional"`
	Output  []string `arg:"positional"`
}
arg.MustParse(&args)
fmt.Println("输入:", args.Input)
fmt.Println("输出:", args.Output)
$ ./example src.txt x.out y.out z.out
输入: src.txt
输出: [x.out y.out z.out]

环境变量

var args struct {
	Workers int `arg:"env"`
}
arg.MustParse(&args)
fmt.Println("工作线程:", args.Workers)
$ WORKERS=4 ./example
工作线程: 4
$ WORKERS=4 ./example --workers=6
工作线程: 6

你也可以覆盖环境变量的名称:

var args struct {
	Workers int `arg:"env:NUM_WORKERS"`
}
arg.MustParse(&args)
fmt.Println("工作线程:", args.Workers)
$ NUM_WORKERS=4 ./example
工作线程: 4

你可以使用CSV(RFC 4180)格式提供多个值:

var args struct {
    Workers []int `arg:"env"`
}
arg.MustParse(&args)
fmt.Println("工作线程:", args.Workers)
$ WORKERS='1,99' ./example
工作线程: [1 99]

你还可以使用与参数名不匹配的环境变量:

var args struct {
	Workers int `arg:"--count,env:NUM_WORKERS"`
}
arg.MustParse(&args)
fmt.Println("工作线程:", args.Workers)
$ NUM_WORKERS=6 ./example
工作线程: 6
$ NUM_WORKERS=6 ./example --count 4
工作线程: 4

使用说明字符串

var args struct {
	Input    string   `arg:"positional"`
	Output   []string `arg:"positional"`
	Verbose  bool     `arg:"-v,--verbose" help:"详细程度"`
	Dataset  string   `help:"使用的数据集"`
	Optimize int      `arg:"-O" help:"优化级别"`
}
arg.MustParse(&args)
$ ./example -h
用法: [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--help] INPUT [OUTPUT [OUTPUT ...]]

位置参数:
  INPUT
  OUTPUT

选项:
  --verbose, -v            详细程度
  --dataset DATASET        使用的数据集
  --optimize OPTIMIZE, -O OPTIMIZE
                           优化级别
  --help, -h               打印此帮助信息

默认值

var args struct {
	Foo string `default:"abc"`
	Bar bool
}
arg.MustParse(&args)

默认值(v1.2之前)

var args struct {
	Foo string
	Bar bool
}
arg.Foo = "abc"
arg.MustParse(&args)

结合命令行选项、环境变量和默认值

你可以结合使用命令行参数、环境变量和默认值。命令行参数优先于环境变量,环境变量优先于默认值。这意味着我们首先检查某个选项是否在命令行上提供,如果没有,我们检查环境变量(仅当提供了env标签时),如果仍未找到,我们检查包含默认值的default标签。

var args struct {
    Test  string `arg:"-t,env:TEST" default:"something"`
}
arg.MustParse(&args)

忽略环境变量和/或默认值

通过忽略环境变量和/或默认值,可以保持现有结构中的值不变。

var args struct {
    Test  string `arg:"-t,env:TEST" default:"something"`
}

p, err := arg.NewParser(arg.Config{
    IgnoreEnv: true,
    IgnoreDefault: true,
}, &args)

err = p.Parse(os.Args)

具有多个值的参数

var args struct {
	Database string
	IDs      []int64
}
arg.MustParse(&args)
fmt.Printf("从%s获取以下ID: %q", args.Database, args.IDs)
./example -database foo -ids 1 2 3
从foo获取以下ID: [1 2 3]

可以多次指定的参数,与位置参数混合使用

var args struct {
    Commands  []string `arg:"-c,separate"`
    Files     []string `arg:"-f,separate"`
    Databases []string `arg:"positional"`
}
arg.MustParse(&args)
./example -c cmd1 db1 -f file1 db2 -c cmd2 -f file2 -f file3 db3 -c cmd3
命令: [cmd1 cmd2 cmd3]
文件: [file1 file2 file3]
数据库: [db1 db2 db3]

具有键和值的参数

var args struct {
	UserIDs map[string]int
}
arg.MustParse(&args)
fmt.Println(args.UserIDs)
./example --userids john=123 mary=456
map[john:123 mary:456]

自定义验证

var args struct {
	Foo string
	Bar string
}
p := arg.MustParse(&args)
if args.Foo == "" && args.Bar == "" {
	p.Fail("你必须提供--foo或--bar")
}
./example
用法: samples [--foo FOO] [--bar BAR]
错误: 你必须提供--foo或--bar

版本字符串

type args struct {
	...
}

func (args) Version() string {
	return "someprogram 4.3.0"
}

func main() {
	var args args
	arg.MustParse(&args)
}
$ ./example --version
someprogram 4.3.0

注意 如果在args或任何子命令中定义了--version标志,它将覆盖内置的版本控制。

覆盖选项名称

var args struct {
	Short        string `arg:"-s"`
	Long         string `arg:"--custom-long-option"`
	ShortAndLong string `arg:"-x,--my-option"`
	OnlyShort    string `arg:"-o,--"`
}
arg.MustParse(&args)
$ ./example --help
用法: example [-o ONLYSHORT] [--short SHORT] [--custom-long-option CUSTOM-LONG-OPTION] [--my-option MY-OPTION]

选项:
  --short SHORT, -s SHORT
  --custom-long-option CUSTOM-LONG-OPTION
  --my-option MY-OPTION, -x MY-OPTION
  -o ONLYSHORT
  --help, -h             显示此帮助并退出

嵌入式结构体

嵌入式结构体的字段与常规字段一样处理:


type DatabaseOptions struct {
	Host     string
	Username string
	Password string
}

type LogOptions struct {
	LogFile string
	Verbose bool
}

func main() {
	var args struct {
		DatabaseOptions
		LogOptions
	}
	arg.MustParse(&args)
}

如常,任何标记为arg:"-"的字段都会被忽略。

支持的类型

以下类型可以用作参数:

  • 内置整数类型:int, int8, int16, int32, int64, byte, rune
  • 内置浮点类型:float32, float64
  • 字符串
  • 布尔值
  • 表示为url.URL的URL
  • 表示为time.Duration的时间持续
  • 表示为mail.Address的电子邮件地址
  • 表示为net.HardwareAddr的MAC地址
  • 以上任何类型的指针
  • 以上任何类型的切片
  • 使用以上任何类型作为键和值的映射
  • 任何实现encoding.TextUnmarshaler的类型

自定义解析

实现encoding.TextUnmarshaler来定义你自己的解析逻辑。

// 接受形如"head.tail"的命令行参数
type NameDotName struct {
	Head, Tail string
}
func (n *NameDotName) UnmarshalText(b []byte) error {
	s := string(b)
	pos := strings.Index(s, ".")
	if pos == -1 {
		return fmt.Errorf("在 %s 中缺少句点", s)
	}
	n.Head = s[:pos]
	n.Tail = s[pos+1:]
	return nil
}

func main() {
	var args struct {
		Name NameDotName
	}
	arg.MustParse(&args)
	fmt.Printf("%#v\n", args.Name)
}
$ ./example --name=foo.bar
main.NameDotName{Head:"foo", Tail:"bar"}

$ ./example --name=oops
用法: example [--name NAME]
错误: 处理 --name 时出错: 在 "oops" 中缺少句点

带默认值的自定义解析

实现 encoding.TextMarshaler 来定义你自己的默认值字符串:

// 接受形如 "head.tail" 的命令行参数
type NameDotName struct {
	Head, Tail string
}

func (n *NameDotName) UnmarshalText(b []byte) error {
	// 与前一个例子相同
}

// 只有当你想在使用说明中显示默认值时才需要这个
func (n *NameDotName) MarshalText() ([]byte, error) {
	return []byte(fmt.Sprintf("%s.%s", n.Head, n.Tail)), nil
}

func main() {
	var args struct {
		Name NameDotName `default:"file.txt"`
	}
	arg.MustParse(&args)
	fmt.Printf("%#v\n", args.Name)
}
$ ./example --help
用法: test [--name NAME]

选项:
  --name NAME [默认值: file.txt]
  --help, -h             显示此帮助信息并退出

$ ./example
main.NameDotName{Head:"file", Tail:"txt"}

自定义占位符

在1.3.0版本中引入

使用 placeholder 标签来控制在使用说明中使用的占位符文本。

var args struct {
	Input    string   `arg:"positional" placeholder:"SRC"`
	Output   []string `arg:"positional" placeholder:"DST"`
	Optimize int      `arg:"-O" help:"优化级别" placeholder:"LEVEL"`
	MaxJobs  int      `arg:"-j" help:"最大同时作业数" placeholder:"N"`
}
arg.MustParse(&args)
$ ./example -h
用法: example [--optimize LEVEL] [--maxjobs N] SRC [DST [DST ...]]

位置参数:
  SRC
  DST

选项:
  --optimize LEVEL, -O LEVEL
                         优化级别
  --maxjobs N, -j N      最大同时作业数
  --help, -h             显示此帮助信息并退出

描述字符串

通过实现返回字符串的 Description 函数,可以在帮助文本顶部添加描述性消息。

type args struct {
	Foo string
}

func (args) Description() string {
	return "该程序执行这个和那个"
}

func main() {
	var args args
	arg.MustParse(&args)
}
$ ./example -h
该程序执行这个和那个
用法: example [--foo FOO]

选项:
  --foo FOO
  --help, -h             显示此帮助信息并退出

类似地,通过实现 Epilogue 函数,可以在帮助文本末尾添加结语。

type args struct {
	Foo string
}

func (args) Epilogue() string {
	return "更多信息请访问 github.com/alexflint/go-arg"
}

func main() {
	var args args
	arg.MustParse(&args)
}
$ ./example -h
用法: example [--foo FOO]

选项:
  --foo FOO
  --help, -h             显示此帮助信息并退出

更多信息请访问 github.com/alexflint/go-arg

子命令

在1.1.0版本中引入

子命令常用于将多个功能分组到单个程序中的工具。一个例子是 git 工具:

$ git checkout [特定于检出代码的参数]
$ git commit [特定于提交的参数]
$ git push [特定于推送的参数]

"checkout"、"commit" 和 "push" 这些字符串与简单的位置参数不同,因为用户可用的选项会根据他们选择的子命令而改变。

这可以在 go-arg 中如下实现:

type CheckoutCmd struct {
	Branch string `arg:"positional"`
	Track  bool   `arg:"-t"`
}
type CommitCmd struct {
	All     bool   `arg:"-a"`
	Message string `arg:"-m"`
}
type PushCmd struct {
	Remote      string `arg:"positional"`
	Branch      string `arg:"positional"`
	SetUpstream bool   `arg:"-u"`
}
var args struct {
	Checkout *CheckoutCmd `arg:"subcommand:checkout"`
	Commit   *CommitCmd   `arg:"subcommand:commit"`
	Push     *PushCmd     `arg:"subcommand:push"`
	Quiet    bool         `arg:"-q"` // 这个标志对所有子命令都是全局的
}

arg.MustParse(&args)

switch {
case args.Checkout != nil:
	fmt.Printf("请求检出分支 %s\n", args.Checkout.Branch)
case args.Commit != nil:
	fmt.Printf("请求提交,消息为 \"%s\"\n", args.Commit.Message)
case args.Push != nil:
	fmt.Printf("请求从 %s 推送到 %s\n", args.Push.Branch, args.Push.Remote)
}

使用子命令时还有一些额外的规则:

  • subcommand 标签只能用于指向结构体的指针字段
  • 包含子命令的任何结构体都不能包含任何位置参数

这个包允许程序接受子命令,但在没有指定子命令时也可以执行其他操作。 另一方面,如果你希望在没有指定子命令时程序终止,推荐的方式是:

p := arg.MustParse(&args)
if p.Subcommand() == nil {
    p.Fail("缺少子命令")
}

API 文档

https://godoc.org/github.com/alexflint/go-arg

原理

Go 有很多命令行参数解析库,包括标准库中的一个,那为什么还要构建另一个呢?

标准库中的 flag 库对我来说似乎有些尴尬。位置参数必须在选项之前,所以 ./prog x --foo=1 会如你所期望的那样工作,但 ./prog --foo=1 x 则不会。它也不允许参数同时具有长格式(--foo)和短格式(-f)。

许多第三方参数解析库非常适合编写复杂的命令行界面,但对于一个只有几个标志的简单脚本来说,对我而言感觉有些过度。

go-arg 背后的想法是,Go 已经有了一种使用结构体描述数据结构的优秀方式,所以没有必要开发额外的抽象层次。go-arg 用单个结构体替代了指定程序接受哪些参数的 API 和获取这些参数值的另一个 API。

向后兼容性说明

此库的早期版本要求帮助文本是 arg 标签的一部分。这仍然受支持,但现在已被弃用。相反,你应该使用上面描述的单独的 help 标签,这消除了你可以编写的文本的大部分限制。特别是,如果你的帮助文本包含任何逗号,你将需要使用新的 help 标签。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

稿定AI

稿定设计 是一个多功能的在线设计和创意平台,提供广泛的设计工具和资源,以满足不同用户的需求。从专业的图形设计师到普通用户,无论是进行图片处理、智能抠图、H5页面制作还是视频剪辑,稿定设计都能提供简单、高效的解决方案。该平台以其用户友好的界面和强大的功能集合,帮助用户轻松实现创意设计。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号