英文:
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 -apply
或 cmd -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)
}
}
答案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.
→_→ 怀疑的眼神~~
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论