Go中的命令行标志可以设置为强制吗?
Can command line flags in Go be set to mandatory?
有没有办法设置某些标志是强制性的,还是我必须自己检查它们的存在?
flag
包不支持强制或必需的标志(意味着必须明确指定标志)。
您可以为(所有)标志使用合理的默认值。而且,如果标志类似于没有合理的默认值,请在应用程序开始时检查该值并停止并显示错误消息。无论如何,您都应该进行标志值验证(不仅仅是针对必需的标志),所以这不应该意味着任何(大)开销,这通常是一个很好的做法。
我喜欢 github.com/jessevdk/go-flags
包在 CLI 中使用。它提供了一个 required
属性,用于设置强制标志:
var opts struct {
...
// Example of a required flag
Name string `short:"n" long:"name" description:"A name" required:"true"`
...
}
与 一样,flag
包不直接提供此功能,通常您可以(并且应该)能够提供合理的默认值。对于只需要少量显式参数(例如输入和输出文件名)的情况,您可以使用位置参数(例如在 flag.Parse()
之后检查 flag.NArg()==2
然后 input, output := flag.Arg(0), flag.Arg(1)
)。
但是,如果您遇到这种情况不明智的情况;说出你想以任何顺序接受的几个整数标志,其中任何整数值都是合理的,但没有默认值。然后你可以使用 flag.Visit
函数来检查你关心的标志是否被显式设置。我认为这是判断标志是否明确设置为其默认值的唯一方法(不计算自定义 flag.Value
类型和保持状态的 Set
实现)。
例如,也许是这样的:
required := []string{"b", "s"}
flag.Parse()
seen := make(map[string]bool)
flag.Visit(func(f *flag.Flag) { seen[f.Name] = true })
for _, req := range required {
if !seen[req] {
// or possibly use `log.Fatalf` instead of:
fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
os.Exit(2) // the same exit code flag.Parse uses
}
}
如果未明确设置“-b”或“-s”标志,这将产生错误。
go-flags
允许您声明必需的标志和必需的位置参数:
var opts struct {
Flag string `short:"f" required:"true" name:"a flag"`
Args struct {
First string `positional-arg-name:"first arg"`
Sencond string `positional-arg-name:"second arg"`
} `positional-args:"true" required:"2"`
}
args, err := flags.Parse(&opts)
如果你有标志路径,只需检查 *path 是否包含一些值
var path = flag.String("f", "", "/path/to/access.log")
flag.Parse()
if *path == "" {
usage()
os.Exit(1)
}
我同意 但是,在我的例子中,默认值通常是环境值。例如,
dsn := flag.String("dsn", os.Getenv("MYSQL_DSN"), "data source name")
在这种情况下,我想检查这些值是通过调用(通常是本地开发)还是环境变量(生产环境)设置的。
所以经过一些小的修改,它适用于我的情况。
使用flag.VisitAll检查所有标志的值。
required := []string{"b", "s"}
flag.Parse()
seen := make(map[string]bool)
flag.VisitAll(func(f *flag.Flag) {
if f.Value.String() != "" {
seen[f.Name] = true
}
})
for _, req := range required {
if !seen[req] {
// or possibly use `log.Fatalf` instead of:
fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
os.Exit(2) // the same exit code flag.Parse uses
}
}
或者你可以 docopt,你只需要写“用法”文本。 Docopt 解释使用文本并创建参数映射。这开辟了很多可能性,都遵循 POSIX 使用文本标准。该库已经支持大约 20 种语言。
https://github.com/docopt/docopt.go
package main
import (
"fmt"
"github.com/docopt/docopt-go"
)
const (
Usage = `Naval Fate.
Usage:
naval_fate ship new <name>...
naval_fate ship <name> move <x> <y> [--speed=<kn>]
naval_fate ship shoot <x> <y>
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
naval_fate -h | --help
naval_fate --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.`
)
func main() {
args, _ := docopt.ParseDoc(Usage)
fmt.Println(args)
}
有没有办法设置某些标志是强制性的,还是我必须自己检查它们的存在?
flag
包不支持强制或必需的标志(意味着必须明确指定标志)。
您可以为(所有)标志使用合理的默认值。而且,如果标志类似于没有合理的默认值,请在应用程序开始时检查该值并停止并显示错误消息。无论如何,您都应该进行标志值验证(不仅仅是针对必需的标志),所以这不应该意味着任何(大)开销,这通常是一个很好的做法。
我喜欢 github.com/jessevdk/go-flags
包在 CLI 中使用。它提供了一个 required
属性,用于设置强制标志:
var opts struct {
...
// Example of a required flag
Name string `short:"n" long:"name" description:"A name" required:"true"`
...
}
与 flag
包不直接提供此功能,通常您可以(并且应该)能够提供合理的默认值。对于只需要少量显式参数(例如输入和输出文件名)的情况,您可以使用位置参数(例如在 flag.Parse()
之后检查 flag.NArg()==2
然后 input, output := flag.Arg(0), flag.Arg(1)
)。
但是,如果您遇到这种情况不明智的情况;说出你想以任何顺序接受的几个整数标志,其中任何整数值都是合理的,但没有默认值。然后你可以使用 flag.Visit
函数来检查你关心的标志是否被显式设置。我认为这是判断标志是否明确设置为其默认值的唯一方法(不计算自定义 flag.Value
类型和保持状态的 Set
实现)。
例如,也许是这样的:
required := []string{"b", "s"}
flag.Parse()
seen := make(map[string]bool)
flag.Visit(func(f *flag.Flag) { seen[f.Name] = true })
for _, req := range required {
if !seen[req] {
// or possibly use `log.Fatalf` instead of:
fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
os.Exit(2) // the same exit code flag.Parse uses
}
}
如果未明确设置“-b”或“-s”标志,这将产生错误。
go-flags
允许您声明必需的标志和必需的位置参数:
var opts struct {
Flag string `short:"f" required:"true" name:"a flag"`
Args struct {
First string `positional-arg-name:"first arg"`
Sencond string `positional-arg-name:"second arg"`
} `positional-args:"true" required:"2"`
}
args, err := flags.Parse(&opts)
如果你有标志路径,只需检查 *path 是否包含一些值
var path = flag.String("f", "", "/path/to/access.log")
flag.Parse()
if *path == "" {
usage()
os.Exit(1)
}
我同意
dsn := flag.String("dsn", os.Getenv("MYSQL_DSN"), "data source name")
在这种情况下,我想检查这些值是通过调用(通常是本地开发)还是环境变量(生产环境)设置的。
所以经过一些小的修改,它适用于我的情况。
使用flag.VisitAll检查所有标志的值。
required := []string{"b", "s"}
flag.Parse()
seen := make(map[string]bool)
flag.VisitAll(func(f *flag.Flag) {
if f.Value.String() != "" {
seen[f.Name] = true
}
})
for _, req := range required {
if !seen[req] {
// or possibly use `log.Fatalf` instead of:
fmt.Fprintf(os.Stderr, "missing required -%s argument/flag\n", req)
os.Exit(2) // the same exit code flag.Parse uses
}
}
或者你可以 docopt,你只需要写“用法”文本。 Docopt 解释使用文本并创建参数映射。这开辟了很多可能性,都遵循 POSIX 使用文本标准。该库已经支持大约 20 种语言。
https://github.com/docopt/docopt.go
package main
import (
"fmt"
"github.com/docopt/docopt-go"
)
const (
Usage = `Naval Fate.
Usage:
naval_fate ship new <name>...
naval_fate ship <name> move <x> <y> [--speed=<kn>]
naval_fate ship shoot <x> <y>
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
naval_fate -h | --help
naval_fate --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.`
)
func main() {
args, _ := docopt.ParseDoc(Usage)
fmt.Println(args)
}