Pflag
pflag 是一个用来替代 go 语言标准库中的 flag 包的第三方包,它实现了 POSIX/GNU 风格的命令行参数解析,支持更多的参数类型和功能,同时也兼容 flag 包的用法,因此我们在使用 pflag 包时,可以将其别名为 flag:
import flag "github.com/spf13/pflag"
为程序设置 flag
指针式
我们可以声明一个 flag 并将其存储在指针中:
func main() {
var port = flag.Int("port", 8080, "specify the listening port number")
flag.Parse()
fmt.Printf("listening to the port: %d\n", *port)
}
编译运行程序:
go build main.go
./main
#listening to the port: 8080
查看帮助信息:
./main -h
#Usage of D:\workspace\golang\src\pflag-demo\temp\main.exe:
# --port int specify the listening port number (default 8080)
#pflag: help requested
传入指定参数:
./main --port=4399
#listening to the port: 4399
变量式
我们可以使用 Var() 函数将 flag 绑定到变量:
func main() {
var port int
flag.IntVar(&port, "port", 8080, "specify the listening port number")
flag.Parse()
fmt.Printf("listening to the port: %d\n", port)
}
运行程序:
go run main.go --port=4399
#listening to the port: 4399
自定义标志类型
我们可以创建满足 Value 接口的自定义标志,对于此类标志,默认值只是变量的初始值。
// Port is custom flag type that satisfies the Value interface.
type Port struct {
value string
}
// String returns the current value of the custom flag.
func (c *Port) String() string {
return c.value
}
// Set sets the value of the custom flag.
func (c *Port) Set(val string) error {
c.value = val
return nil
}
// Type returns the type of the custom flag.
func (c *Port) Type() string {
return "port"
}
func main() {
var port Port
flag.Var(&port, "port", "specify the listening port number")
flag.Parse()
fmt.Printf("listening to the port: %s\n", port)
}
运行程序:
go run main.go
#listening to the port: {}
go run main.go --port=4399
#listening to the port: {4399}
flag set
我们可以创建多组独立的 flag:
func main() {
FS1 := flag.NewFlagSet("FS1", flag.ExitOnError)
port := FS1.String("port", "8080", "specify the listening port number")
FS2 := flag.NewFlagSet("FS2", flag.ExitOnError)
addr := FS2.String("addr", "127.0.0.1", "specify the http address")
if len(os.Args) < 2 {
fmt.Println("must use flag set.")
os.Exit(1)
}
switch os.Args[1] {
case "FS1":
_ = FS1.Parse(os.Args[2:])
fmt.Printf("listening to port: %s\n", *port)
case "FS2":
_ = FS2.Parse(os.Args[2:])
fmt.Printf("listening to addr: %s\n", *addr)
default:
fmt.Println("no such flag set exists.")
}
}
运行程序:
go run main.go
#must use flag set.
#exit status 1
go run main.go FS1 --port=4399
#listening to port: 4399
go run main.go FS2 --addr=localhost
#listening to addr: localhost
辅助函数
我们可以使用辅助函数来获取 flag set 中 flag 的值:
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
var port int
fs.IntVar(&port, "port", 8080, "specify the listening port number")
_ = fs.Parse(os.Args[1:])
n, _ := fs.GetInt("port")
fmt.Println("listening to port:", n)
fmt.Println("listening to port:", port)
}
运行程序:
go run main.go --port=4399
#listening to port: 4399
#listening to port: 4399
额外参数
我们可以使用 flag.Args() 来获取非标志参数,也可以使用 flag.Arg(i) 来逐个获取参数。
func main() {
port := flag.String("port", "8080", "specify the listening port number")
flag.Parse()
fmt.Printf("listening to port: %s\n", *port)
for i := 0; i < len(flag.Args()); i++ {
fmt.Printf("additional arg %d : %s\n", i, flag.Arg(i))
}
}
运行程序:
go run main.go 4399 7k7k 2144
#listening to port: 8080
#additional arg 0 : 4399
#additional arg 1 : 7k7k
#additional arg 2 : 2144
简写标志
我们可以为 flag 提供简写:
func main() {
port := flag.IntP("port", "p", 8080, "specify the listening port number")
flag.Parse()
fmt.Printf("listening to port: %d\n", *port)
}
运行程序:
go run main.go -p=4399
#listening to port: 4399
无选项默认值
我们可以为 flag 设置无选项默认值(NoOptDefVal),无选项默认值指的是使用 flag 但没有提供选项(参数)时,flag 被赋予的默认值。
func main() {
var port int
flag.IntVarP(&port, "port", "p", 8080, "specify the listening port number")
flag.Lookup("port").NoOptDefVal = "4399"
flag.Parse()
fmt.Printf("listening to port: %d\n", port)
}
运行程序:
go run main.go
#listening to port: 8080
go run main.go -p
#listening to port: 4399
go run main.go -p=2144
#listening to port: 2144
命名标准化
命名转换
我们可以自定义标准化函数,将输入的 flag 名 转换为标准的 flag 名:
func wordSepNormalizeFunc(f *flag.FlagSet, name string) flag.NormalizedName {
from := []string{"-", "_"}
to := "."
for _, sep := range from {
name = strings.Replace(name, sep, to, -1)
}
return flag.NormalizedName(name)
}
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
fs.SetNormalizeFunc(wordSepNormalizeFunc)
fs.String("http.port", "8080", "specify the listening port number")
_ = fs.Parse(os.Args[1:])
port := fs.Lookup("http.port").Value.String()
fmt.Println("listening to port:", port)
}
运行程序:
go run main.go --http-port=4399
#listening to port: 4399
go run main.go --http_port=4399
#listening to port: 4399
go run main.go --http.port=4399
#listening to port: 4399
别名
我们可以自定义别名函数,为 flag 添加别名:
func aliasNormalizeFunc(f *flag.FlagSet, name string) flag.NormalizedName {
switch name {
case "portNum":
name = "port"
break
}
return flag.NormalizedName(name)
}
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
fs.SetNormalizeFunc(aliasNormalizeFunc)
fs.String("port", "8080", "specify the listening port number")
_ = fs.Parse(os.Args[1:])
port := fs.Lookup("port").Value.String()
fmt.Println("listening to port:", port)
}
运行程序:
go run main.go --portNum=4399
#listening to port: 4399
弃用
我们可以弃用 flag 或 flag 的简写,弃用的 flag 或简写不会出现在帮助信息中,当我们使用弃用的 flag 或简写,控制台会打印弃用信息。
标志
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
var port int
fs.IntVar(&port, "port", 8080, "specify the listening port number")
_ = fs.MarkDeprecated("port", "please use --portNum instead.")
_ = fs.Parse(os.Args[1:])
}
编译程序,然后查看帮助信息:
go build main.go
./main -h
#Usage of fs:
#pflag: help requested
运行程序:
./main -p=4399
#Flag shorthand -p has been deprecated, please use --port only
简写
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
var port int
fs.IntVarP(&port, "port", "p", 8080, "specify the listening port number")
_ = fs.MarkShorthandDeprecated("port", "please use --port only")
_ = fs.Parse(os.Args[1:])
}
编译程序,然后查看帮助信息:
go build main.go
./main -h
#Usage of fs:
# --port int specify the listening port number (default 8080)
#pflag: help requested
运行程序:
./main -p=4399
#Flag shorthand -p has been deprecated, please use --port only
隐藏 flag
我们可以将 flag 设置为隐藏,隐藏的 flag 仍可以使用,但是不会显示在帮助信息中。
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
var secretFlagValue string
fs.StringVar(&secretFlagValue, "secretFlag", "", "A secret flag for internal use")
_ = fs.MarkHidden("secretFlag")
_ = fs.Parse(os.Args[1:])
fmt.Println("secretFlag value:", secretFlagValue)
}
编译程序,然后查看帮助信息:
go build main.go
./main -h
#Usage of fs:
#pflag: help requested
使用隐藏参数:
./main --port=4399
#listening to port: 4399
禁用排序
默认情况下,我们定义的 flag 在帮助信息中会首字母的顺序排序,我们可以手动关闭。
func main() {
fs := flag.NewFlagSet("fs", flag.ExitOnError)
fs.String("C", "", "it's flag C.")
fs.String("B", "", "it's flag B.")
fs.String("A", "", "it's flag A.")
fmt.Println("Flags:")
fs.PrintDefaults()
fmt.Println("===============================")
fs.SortFlags = false
fmt.Println("Flags:")
fs.PrintDefaults()
}
运行程序:
go run main.go
#Flags:
# --A string it's flag A.
# --B string it's flag B.
# --C string it's flag C.
#===============================
#Flags:
# --C string it's flag C.
# --B string it's flag B.
# --A string it's flag A.
本文由 Sue211213 原创,发表于 2023 年 8 月 10 日,转载请注明出处和作者,谢谢!