亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

全局標志和子命令

全局標志和子命令

Go
炎炎設計 2022-09-05 15:48:03
我正在實現一個帶有多個子命令的小CLI。我想支持全局標志,即適用于所有子命令以避免重復它們的標志。例如,在下面的示例中,我試圖擁有所有子命令所需的標志。-requiredpackage mainimport (    "flag"    "fmt"    "log"    "os")var (    required = flag.String(        "required",        "",        "required for all commands",    )    fooCmd = flag.NewFlagSet("foo", flag.ExitOnError)    barCmd = flag.NewFlagSet("bar", flag.ExitOnError))func main() {    flag.Parse()    if *required == "" {        fmt.Println("-required is required for all commands")    }    switch os.Args[1] {    case "foo":        fooCmd.Parse(os.Args[2:])        fmt.Println("foo")    case "bar":        barCmd.Parse(os.Args[2:])        fmt.Println("bar")    default:        log.Fatalf("[ERROR] unknown subcommand '%s', see help for more details.", os.Args[1])    }}我希望用法是這樣的:$ go run main.go foo -required helloworld但是如果我用上面的代碼運行它,我得到:$ go run main.go foo -required hello-required is required for all commandsflag provided but not defined: -requiredUsage of foo:exit status 2它看起來像是沒有從CLI捕獲,然后抱怨我給了它一個它無法識別的標志。flag.Parse()-requiredfooCmd在 Golang 中使用帶有全局標志的子命令的最簡單方法是什么?
查看完整描述

2 回答

?
楊__羊羊

TA貢獻1943條經驗 獲得超7個贊

如果打算實現子命令,則不應調用 flag。解析())。


相反,請決定使用哪個子命令(就像您所做的那樣),并僅調用其 FlagSet.Parse() 方法。os.Args[1]


是的,要使此操作有效,所有標志集都應包含公共標志。但是,只需注冊一次(在一個地方)就很容易了。創建包級別變量:


var (

    required string


    fooCmd = flag.NewFlagSet("foo", flag.ExitOnError)

    barCmd = flag.NewFlagSet("bar", flag.ExitOnError)

)

使用循環遍歷所有標志集,并注冊公共標志,使用FlagSet.StringVar()指向您的變量:


func setupCommonFlags() {

    for _, fs := range []*flag.FlagSet{fooCmd, barCmd} {

        fs.StringVar(

            &required,

            "required",

            "",

            "required for all commands",

        )

    }

}

并在調用適當的標志集,并在之后進行測試:main()Parse()required


func main() {

    setupCommonFlags()


    switch os.Args[1] {

    case "foo":

        fooCmd.Parse(os.Args[2:])

        fmt.Println("foo")

    case "bar":

        barCmd.Parse(os.Args[2:])

        fmt.Println("bar")

    default:

        log.Fatalf("[ERROR] unknown subcommand '%s', see help for more details.", os.Args[1])

    }


    if required == "" {

        fmt.Println("-required is required for all commands")

    }

}

您可以通過創建標志集映射來改進上述解決方案,因此可以使用該映射注冊公共標志,還可以執行解析。


完整應用:


var (

    required string


    fooCmd = flag.NewFlagSet("foo", flag.ExitOnError)

    barCmd = flag.NewFlagSet("bar", flag.ExitOnError)

)


var subcommands = map[string]*flag.FlagSet{

    fooCmd.Name(): fooCmd,

    barCmd.Name(): barCmd,

}


func setupCommonFlags() {

    for _, fs := range subcommands {

        fs.StringVar(

            &required,

            "required",

            "",

            "required for all commands",

        )

    }

}


func main() {

    setupCommonFlags()


    cmd := subcommands[os.Args[1]]

    if cmd == nil {

        log.Fatalf("[ERROR] unknown subcommand '%s', see help for more details.", os.Args[1])

    }


    cmd.Parse(os.Args[2:])

    fmt.Println(cmd.Name())


    if required == "" {

        fmt.Println("-required is required for all commands")

    }

}


查看完整回答
反對 回復 2022-09-05
?
翻翻過去那場雪

TA貢獻2065條經驗 獲得超14個贊

將全局標志放在子命令之前:


go run . -required=x foo.


使用代替 :flag.Args()os.Args


package main


import (

    "flag"

    "fmt"

    "log"

    "os"

)


var (

    required = flag.String(

        "required",

        "",

        "required for all commands",

    )   

    fooCmd = flag.NewFlagSet("foo", flag.ExitOnError)

    barCmd = flag.NewFlagSet("bar", flag.ExitOnError)

)


func main() {

    flag.Parse()


    if *required == "" {

        fmt.Println("-required is required for all commands")

    }   


    args := flag.Args() // everything after the -required flag, e.g. [foo, -foo-flag-1, -foo-flag-2, ...]

    switch args[0] {

    case "foo":

        fooCmd.Parse(args[1:])

        fmt.Println("foo")

    case "bar":

        barCmd.Parse(args[1:])

        fmt.Println("bar")

    default:

        log.Fatalf("[ERROR] unknown subcommand '%s', see help for more details.", args[0])

    }   

}

如果要將所有標志放在一起,請在子命令之后編寫一個幫助程序函數,該函數將公共標志添加到每個標志集:


var (

    fooCmd = flag.NewFlagSet("foo", flag.ExitOnError)

    barCmd = flag.NewFlagSet("bar", flag.ExitOnError)

)


type globalOpts struct {

    required string

}


func main() {

    var opts globalOpts


    addGlobalFlags(fooCmd, &opts)

    addGlobalFlags(barCmd, &opts)


    if opts.required == "" {

        fmt.Println("-required is required for all commands")

    } 


    // ...

}


func addGlobalFlags(fs *flag.FlagSet, opts *globalOpts) {

    fs.StringVar(

        &opts.required,

        "required",

        "",

        "required for all commands",

    )

}

也許您還可以將這兩種方法結合起來,使全局標志在任何位置工作。


查看完整回答
反對 回復 2022-09-05
  • 2 回答
  • 0 關注
  • 161 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號