如何在Golang中使用flag包指定位置参数?

huangapple go评论124阅读模式
英文:

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() &lt; 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&#39;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)
}

huangapple
  • 本文由 发表于 2014年8月9日 11:58:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/25215088.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定