Go 语言的 GNU 风格命令行参数解析器:argp
`argp` 是一个 Go 语言实现的 GNU 风格命令行参数解析库。它支持标准 GNU 命令行规范,包括短选项、长选项、选项值、参数嵌套和子命令。该库通过标签将参数映射到结构体字段,支持数组、切片、结构体等复合类型,并提供内置的帮助信息。文章还介绍了安装、基本用法、子命令、参数和选项的详细示例,以及 `Count`、`Append`、`Config`、`List` 和 `Dict` 等高级特性。
GNU 命令行参数解析器
License
这个库 argp
提供了一个遵循 GNU 标准的命令行参数解析器。
./test -vo out.png --size 256 input.txt
它具有以下特性:
- 内置的帮助信息 (
-h
和--help
) - 使用标签将参数扫描到结构体字段中,方便配置
- 支持扫描到复合类型字段(数组、切片、结构体)
- 允许嵌套子命令
GNU 命令行参数规则:
- 以连字符
-
开头的参数是选项 - 多个选项可以组合:
-abc
等同于-a -b -c
- 长选项以两个连字符开头:
--abc
是一个选项 - 选项名称由字母数字字符组成
- 选项可以有值:
-a 1
表示a
的值为1
- 选项值可以用空格、等号或不使用分隔符:
-a1 -a=1 -a 1
都是等价的 - 选项和非选项可以交错出现
- 参数
--
终止所有选项,之后的所有参数都被视为非选项 - 单个
-
参数是一个非选项,通常用于表示标准输入或输出流 - 选项可以多次指定,只有最后一个值有效
- 选项可以有多个值:
-a 1 2 3
表示a
是一个包含三个数字的数组/切片/结构体[1,2,3]
另请参阅github.com/tdewolff/prompt,这是一个命令行提示器。
安装
确保已安装 Git 和 Go (1.22 或更高版本),运行以下命令:
mkdir Project
cd Project
go mod init
go get -u github.com/tdewolff/argp
然后添加以下导入:
import (
"github.com/tdewolff/argp"
)
示例
默认用法
一个包含短选项和长选项的常规命令。 参见 cmd/test/main.go
。
package main
import "github.com/tdewolff/argp"
func main() {
var verbose int
var input string
var output string
var files []string
size := 512 // 默认值
cmd := argp.New("CLI tool description")
cmd.AddOpt(argp.Count{&verbose}, "v", "verbose", "Increase verbosity, eg. -vvv")
cmd.AddOpt(&output, "o", "output", "Output file name")
cmd.AddOpt(&size, "", "size", "Image size")
cmd.AddArg(&input, "input", "Input file name")
cmd.AddRest(&files, "files", "Additional files")
cmd.Parse()
// ...
}
帮助输出:
Usage: test [options] input files...
Options:
-h, --help Help
-o, --output string Output file name
--size=512 int Image size
-v, --verbose int Increase verbosity, eg. -vvv
Arguments:
input Input file name
files Additional files
子命令
使用子命令的示例,当未使用子命令时使用主命令,以及名为 "cmd" 的子命令。 对于主命令,我们也可以使用 New
和 AddOpt
代替,并在 argp.Parse()
后处理该命令。
package main
import "github.com/tdewolff/argp"
func main() {
cmd := argp.NewCmd(&Main{}, "CLI tool description")
cmd.AddCmd(&Command{}, "cmd", "Sub command")
cmd.Parse()
}
type Main struct {
Version bool `short:"v"`
}
func (cmd *Main) Run() error {
// ...
return nil
}
type Command struct {
Verbose bool `short:"v" name:""`
Output string `short:"o" desc:"Output file name"`
Size int `default:"512" desc:"Image size"`
}
func (cmd *Command) Run() error {
// ...
return nil
}
参数
var input string
cmd.AddArg(&input, "input", "Input file name")
var files []string
cmd.AddRest(&files, "files", "Additional input files")
选项
基本类型:
var v string = "default"
cmd.AddOpt(&v, "v", "var", "description")
var v bool = true
cmd.AddOpt(&v, "v", "var", "description")
var v int = 42 // also: int8, int16, int32, int64
cmd.AddOpt(&v, "v", "var", "description")
var v uint = 42 // also: uint8, uint16, uint32, uint64
cmd.AddOpt(&v, "v", "var", "description")
var v float64 = 4.2 // also: float32
cmd.AddOpt(&v, "v", "var", "description")
复合类型:
v := [2]int{4, 2} // element can be any valid basic or composite type
cmd.AddOpt(&v, "v", "var", "description")
// --var [4 2] => [2]int{4, 2}
// or: --var 4,2 => [2]int{4, 2}
v := []int{4, 2, 1} // element can be any valid basic or composite type
cmd.AddOpt(&v, "v", "var", "description")
// --var [4 2 1] => []int{4, 2, 1}
// or: --var 4,2,1 => []int{4, 2, 1}
v := map[int]string{1:"one", 2:"two"} // key and value can be any valid basic or composite type
cmd.AddOpt(&v, "v", "var", "description")
// --var {1:one 2:two} => map[int]string{1:"one", 2:"two"}
v := struct { // fields can be any valid basic or composite type
S string
I int
B [2]bool
}{"string", 42, [2]bool{0, 1}}
cmd.AddOpt(&v, "v", "var", "description")
// --var {string 42 [0 1]} => struct{S string, I int, B [2]bool}{"string", 42, false, true}
Count
统计标志被传递的次数。
var c int
cmd.AddOpt(argp.Count{&c}, "c", "count", "Count")
// Count the number of times flag is present
// -c -c / -cc / --count --count => 2
// or: -c 5 => 5
Append
将每个标志附加到列表中。
var v []int
cmd.AddOpt(argp.Append{&v}, "v", "value", "Values")
// Append values for each flag
// -v 1 -v 2 => [1 2]
Config
从配置文件加载所有参数。 目前仅支持 TOML。
cmd.AddOpt(&argp.Config{cmd, "config.toml"}, "", "config", "Configuration file")
List
使用指定为 type:list
的列表源。 默认支持的类型有:inline。
- Inline 接受一个
[]string
,例如inline:[foo bar]
list := argp.NewList(il)
defer list.Close()
cmd.AddOpt(&list, "", "list", "List")
您可以添加 MySQL 源:
type mysqlList struct {
Hosts string
User string
Password string
Dbname string
Query string
}
func newMySQLList(s []string) (argp.ListSource, error) {
if len(s) != 1 {
return nil, fmt.Errorf("invalid path")
}
t := mysqlList{}
if err := argp.LoadConfigFile(&t, s[0]); err != nil {
return nil, err
}
uri := fmt.Sprintf("%s:%s@%s/%s", t.User, t.Password, t.Hosts, t.Dbname)
db, err := sqlx.Open("mysql", uri)
if err != nil {
return nil, err
}
db.SetConnMaxLifetime(time.Minute)
db.SetConnMaxIdleTime(time.Minute)
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(10)
return argp.NewSQLList(db, t.Query, "")
}
// ...
list.AddSource("mysql", newMySQLList)
// ...
使用方式:./bin -list mysql:list-config.toml
。
Dict
使用指定为 type:dict
的字典源。 默认支持的类型有:static 和 inline。
- Static 接受一个字符串,并将其作为所有键的值返回,例如
static:foobar
- Inline 接受一个
map[string]string
,例如inline:{foo:1 bar:2}
dict := argp.NewDict([]string{"static:value"})
defer dict.Close()
cmd.AddOpt(&dict, "", "dict", "Dict")
您可以像上面的 mysqlList
示例一样添加自定义源。
选项标签
以下结构将接受以下选项和参数:
-v
或--var
,默认值为 42- 第一个名为
first
的参数,默认值为 4.2 - 其他名为
rest
的参数
type Command struct {
Var1 int `short:"v" name:"var" default:"42" desc:"Description"`
Var2 float64 `name:"first" index:"0" default:"4.2"`
Var3 []string `name:"rest" index:"*"`
}
func (cmd *Command) Run() error {
// run command
return nil
}
License
在 MIT license 下发布。