在Go语言中定义独立的FlagSets(标志集)

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

Defining Independent FlagSets in GoLang

问题

根据你提供的内容,以下是翻译的结果:

Go文档(http://golang.org/pkg/flag/)中提到:

FlagSet类型允许定义独立的标志集,例如用于实现命令行界面中的子命令。

我需要这个功能,但我无法弄清楚如何说服flag包来实现它。当我定义两个FlagSets时,解析其中一个会导致错误和警告,如果命令行中的标志是为第二个FlagSet准备的。例如:

f1 := flag.NewFlagSet("f1", flag.ContinueOnError)
apply := f1.Bool("apply", false, "")
silent := f1.Bool("silent", false, "")
if err := f1.Parse(os.Args[1:]); err == nil {
    fmt.Println(*apply, *silent)
}
f2 := flag.NewFlagSet("f2", flag.ContinueOnError)
reset := f2.Bool("reset", false, "")
if err := f2.Parse(os.Args[1:]); err == nil {
    fmt.Println(*reset)
}

如果我尝试执行 cmd -applycmd -reset,我会收到各种警告。我希望保持这些FlagSets分开,因为我只希望 -silent-apply 有效。

我漏掉了什么?

英文:

The Go documentation (http://golang.org/pkg/flag/) says:

> The FlagSet type allows one to define independent sets of flags, such as to implement subcommands in a command-line interface.

I need this functionality but I can't figure out how to persuade the flag pkg to do it. When I define two FlagSets, parsing one of them will give me errors and warnings if the commandline has flags that are meant for the second one. Example:

f1 := flag.NewFlagSet("f1", flag.ContinueOnError)
apply := f1.Bool("apply", false, "")
silent := f1.Bool("silent", false, "")
if err := f1.Parse(os.Args[1:]); err == nil {
    fmt.Println(*apply, *silent)
}
f2 := flag.NewFlagSet("f2", flag.ContinueOnError)
reset := f2.Bool("reset", false, "")
if err := f2.Parse(os.Args[1:]); err == nil {
    fmt.Println(*reset)
}

I get all sorts of warnings if I try to do cmd -apply OR cmd -reset. I want to keep these FlagSets separate because I want to only have -silent work for -apply.

What am I missing?

答案1

得分: 52

你需要首先区分子命令,然后在正确的FlagSet上调用Parse

f1 := flag.NewFlagSet("f1", flag.ContinueOnError)
silent := f1.Bool("silent", false, "")

f2 := flag.NewFlagSet("f2", flag.ContinueOnError)
loud := f2.Bool("loud", false, "")

switch os.Args[1] {
  case "apply":
    if err := f1.Parse(os.Args[2:]); err == nil {
      fmt.Println("apply", *silent)
    }
  case "reset":
    if err := f2.Parse(os.Args[2:]); err == nil {
      fmt.Println("reset", *loud)
    }
}

http://play.golang.org/p/eaEEx_EReX

英文:

You are meant to distinguish between subcommands first, and then call Parse on the right FlagSet.

f1 := flag.NewFlagSet("f1", flag.ContinueOnError)
silent := f1.Bool("silent", false, "")
f2 := flag.NewFlagSet("f2", flag.ContinueOnError)
loud := f2.Bool("loud", false, "")

switch os.Args[1] {
  case "apply":
    if err := f1.Parse(os.Args[2:]); err == nil {
      fmt.Println("apply", *silent)
    }
  case "reset":
    if err := f2.Parse(os.Args[2:]); err == nil {
      fmt.Println("reset", *loud)
    }
}

http://play.golang.org/p/eaEEx_EReX

答案2

得分: 0

原来可以在捕获第一组未识别的标志时消耗一组标志,并且可以丢弃标志包准备发出的错误消息,每当它遇到一个无法识别的选项时。

以下是一种实现方法。

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

func gentleParse(flagset *flag.FlagSet, args []string) []string {
	if len(args) == 0 {
		return nil
	}

	r := make([]string, 0, len(args))

	flagset.Init(flagset.Name(), flag.ContinueOnError)
	w := flagset.Output()
	flagset.SetOutput(ioutil.Discard)
	defer flagset.SetOutput(w)

	next := args

	for len(next) > 0 {
		if next[0] == "--" {
			r = append(r, next...)
			break
		}
		if !strings.HasPrefix(next[0], "-") {
			r, next = append(r, next[0]), next[1:]
			continue
		}
		if err := flagset.Parse(next); err != nil {
			const prefix = "flag provided but not defined: "
			if strings.HasPrefix(err.Error(), prefix) {
				pull := strings.TrimPrefix(err.Error(), prefix)
				for next[0] != pull {
					next = next[1:]
				}
				r, next = append(r, next[0]), next[1:]
				continue
			}
			fmt.Fprintf(w, "%s\n", err)
			flagset.SetOutput(w)
			flag.Usage()
			os.Exit(1)
		}

		next = flag.Args()
	}
	return r
}
英文:

Turns out it is possible to consume one set of flags while capturing the flags not recognized by the first set and while discarding the error messages that the flag package is prepared to emit whenever it runs into an option it doesn't recognize.

Here's one way to do it.

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

func gentleParse(flagset *flag.FlagSet, args []string) []string {
	if len(args) == 0 {
		return nil
	}

	r := make([]string, 0, len(args))

	flagset.Init(flagset.Name(), flag.ContinueOnError)
	w := flagset.Output()
	flagset.SetOutput(ioutil.Discard)
	defer flagset.SetOutput(w)

	next := args

	for len(next) > 0 {
		if next[0] == "--" {
			r = append(r, next...)
			break
		}
		if !strings.HasPrefix(next[0], "-") {
			r, next = append(r, next[0]), next[1:]
			continue
		}
		if err := flagset.Parse(next); err != nil {
			const prefix = "flag provided but not defined: "
			if strings.HasPrefix(err.Error(), prefix) {
				pull := strings.TrimPrefix(err.Error(), prefix)
				for next[0] != pull {
					next = next[1:]
				}
				r, next = append(r, next[0]), next[1:]
				continue
			}
			fmt.Fprintf(w, "%s\n", err)
			flagset.SetOutput(w)
			flag.Usage()
			os.Exit(1)
		}

		next = flag.Args()
	}
	return r
}

答案3

得分: -2

只需将以下代码更改为:

f2.Parse(os.Args[1:])
fmt.Println(*reset)

但警告仍然会显示在控制台上。如果您想要删除它,请修改/usr/local/go/src/flag/flag.go并重新编译golang,或者复制一份flag包。

英文:

Just change these code

if err := f2.Parse(os.Args[1:]); err == nil {
fmt.Println(*reset)
}

to

f2.Parse(os.Args[1:])
fmt.Println(*reset)

but the warning is just left on the console.if u wanna remove it ,modify /usr/local/go/src/flag/flag.go and recompile the golang ..
or do a copy of flag package.

  →_→ 怀疑的眼神~~

huangapple
  • 本文由 发表于 2014年7月1日 14:49:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/24504024.html
匿名

发表评论

匿名网友

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

确定