英文:
How to specify positional arguments with the flag package in Golang?
问题
有时候我想在命令行中传递一个没有名称的参数,比如像 wc
这样的命令,它以文件名作为输入:
wc filename.txt
使用 flag 包,似乎每个参数都必须有一个名称,并且可以指定默认值:
filename := flag.String("filename", "foo.txt", "要统计单词的文件")
然而,我不想要默认值,如果未指定参数,我希望程序退出并显示错误代码。如何向 Go 二进制文件添加一个必需的参数?
我还希望能够解析带有类型信息的参数,所以直接检查 Args() 并不能完全满足需求。
英文:
Sometimes I want to pass an argument on the command line with no name, say a command like wc
, which takes a filename as input:
wc filename.txt
With the flag package, it looks like every flag has to be given a name, with a default value if unspecified.
filename := flag.String("filename", "foo.txt", "Which file to count the words for")
However I don't want a default value, I want the program to exit with an error code if an argument is not specified. How would I add a required argument to a Go binary?
I would also like to be able to parse arguments with type information, so just checking the Args() directly doesn't quite do it.
答案1
得分: 21
你只需要检查flag.NArg()
。
从https://golang.org/pkg/flag/#NArg:
> NArg是在处理标志后剩余的参数数量。
flag.Parse()
if flag.NArg() == 0 {
flag.Usage()
os.Exit(1)
}
英文:
You just have to check flag.NArg()
.
From https://golang.org/pkg/flag/#NArg:
> NArg is the number of arguments remaining after flags have been processed.
flag.Parse()
if flag.NArg() == 0 {
flag.Usage()
os.Exit(1)
}
答案2
得分: 3
你还可以使用flag.NArg()函数来确保你拥有所需数量的位置参数,尽管我不知道它相比于len(flag.Args())有什么优势。
if flag.NArg() < minArgs {
// 做一些操作
...
}
英文:
You can also use the flag.Narg() function to ensure you have the required number of positional arguments, though I don't know what it gives you over len(flag.Args())
if flag.NArg() < minArgs {
// do something
...
}
答案3
得分: 3
如果有人对标准的flag
包行为不满意,因为它在遇到第一个位置参数时会停止解析,你可以使用这些小型库函数以一种可以在位置参数之前或之后指定标志的方式来解析标志。
// ParseFlags解析命令行参数,允许在位置参数之后指定标志。
func ParseFlags() error {
return ParseFlagSet(flag.CommandLine, os.Args[1:])
}
// ParseFlagSet的工作方式类似于flagset.Parse(),但不要求位置参数必须在标志参数之后。
func ParseFlagSet(flagset *flag.FlagSet, args []string) error {
var positionalArgs []string
for {
if err := flagset.Parse(args); err != nil {
return err
}
// 消耗所有被解析为标志的标志。
args = args[len(args)-flagset.NArg():]
if len(args) == 0 {
break
}
// 还剩下至少一个标志,由于我们消耗了所有被解析为标志的参数,所以它必须是一个位置参数。只消耗第一个参数,并重新尝试解析,因为后续的参数可能是标志。
positionalArgs = append(positionalArgs, args[0])
args = args[1:]
}
// 仅解析位置参数,以便flagset.Args()/flagset.NArgs()返回预期的值。
// 注意:这应该永远不会返回错误。
return flagset.Parse(positionalArgs)
}
英文:
In case anyone is unsatisfied with the standard flag
package behavior of stopping the parse as soon as it sees the first positional arg, you can use these small library functions to parse flags in a way that flags can come before or after positional args.
// ParseFlags parses the command line args, allowing flags to be
// specified after positional args.
func ParseFlags() error {
return ParseFlagSet(flag.CommandLine, os.Args[1:])
}
// ParseFlagSet works like flagset.Parse(), except positional arguments are not
// required to come after flag arguments.
func ParseFlagSet(flagset *flag.FlagSet, args []string) error {
var positionalArgs []string
for {
if err := flagset.Parse(args); err != nil {
return err
}
// Consume all the flags that were parsed as flags.
args = args[len(args)-flagset.NArg():]
if len(args) == 0 {
break
}
// There's at least one flag remaining and it must be a positional arg since
// we consumed all args that were parsed as flags. Consume just the first
// one, and retry parsing, since subsequent args may be flags.
positionalArgs = append(positionalArgs, args[0])
args = args[1:]
}
// Parse just the positional args so that flagset.Args()/flagset.NArgs()
// return the expected value.
// Note: This should never return an error.
return flagset.Parse(positionalArgs)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论