【问题标题】:How can I invoke a default subcommand with cobra?如何使用 cobra 调用默认子命令?
【发布时间】:2022-01-11 01:56:46
【问题描述】:

使用 cobra,如果我的应用在没有特定操作(但参数)的情况下被调用,我想运行一个默认命令:

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
    Use:   "mbmd",
    Short: "ModBus Measurement Daemon",
    Long:  "Easily read and distribute data from ModBus meters and grid inverters",

    Run: func(cmd *cobra.Command, args []string) {
        run(cmd, args)
    },
}

但是,由于根命令没有所有参数,因此子命令失败了,因为它现在显然知道子命令的参数:

❯ go run main.go -d sma:126@localhost:5061 --api 127.1:8081 -v
Error: unknown shorthand flag: 'd' in -d

相对于:

❯ go run main.go run -d sma:126@localhost:5061 --api 127.1:8081 -v
2019/07/29 20:58:10 mbmd unknown version (unknown commit)

如何以编程方式实例化/调用子命令?

【问题讨论】:

  • 致电run()。 Cobra 中的每个命令都只是调用一个函数。您可以从多个 cobra 命令调用相同的函数。
  • 和我一样?这仅尊重根命令参数,但不尊重运行命令的参数:/
  • 您现在(2021 年 10 月)有两种可能的解决方法。见my answer below

标签: go go-cobra


【解决方案1】:

这是另一个解决方案:

    cmd, _, err := rootCmd.Find(os.Args[1:])
    // default cmd if no cmd is given
    if err == nil && cmd.Use == rootCmd.Use && cmd.Flags().Parse(os.Args[1:]) != pflag.ErrHelp {
        args := append([]string{defaultCmd.Use}, os.Args[1:]...)
        rootCmd.SetArgs(args)
    }

    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    } 

defaultCmd 替换为您想要的默认值

如果没有设置参数,这部分cmd.Flags().Parse(os.Args[1:]) != pflag.ErrHelp 保持帮助命令为 root 命令工作

【讨论】:

    【解决方案2】:

    2021 年 3 月:您可能会考虑采用spf13/cobra issue 823 中介绍的解决方法

    func subCommands() (commandNames []string) {
        for _, command := range cmd.Commands() {
            commandNames = append(commandNames, append(command.Aliases, command.Name())...)
        }
        return
    }
    
    func setDefaultCommandIfNonePresent() {
        if len(os.Args) > 1 { 
            potentialCommand := os.Args[1]
            for _, command := range subCommands() {
                if command == potentialCommand {
                    return
                }
            }
            os.Args = append([]string{os.Args[0], "<default subcommand>"}, os.Args[1:]...)
        }
    
    }
    
    func main() {
        setDefaultCommandIfNonePresent()
        if err := cmd.Execute(); err != nil {
            zap.S().Error(err)
            os.Exit(1)
        }
    }
    

    这里的区别在于它在更改默认子命令之前检查是否len(os.Args) &gt; 1

    这意味着,如果在没有任何参数的情况下运行,它将打印默认帮助命令(包含所有子命令)。
    否则,如果提供了任何参数,它将使用子命令。

    因此,它将显示不带参数的主“help”,如果提供了“-h”/“--help”,则会显示子命令的帮助。


    或者(2021 年 10 月),来自 authorPR 823

    对此的最新解决方案如下:

    main.go

    func main() {
      // Define the default sub command 'defCmd' here. If user doesn't submit
      // using a default command, we'll use what is here.
      defCmd:="mydefaultcmd"
      cmd.Execute(defCmd)
    }
    

    root.go

    func Execute(defCmd string) {
      var cmdFound bool
      cmd :=rootCmd.Commands()
    
      for _,a:=range cmd{
        for _,b:=range os.Args[1:] {
          if a.Name()==b {
           cmdFound=true
            break
          }
        }
      }
      if !cmdFound {
        args:=append([]string{defCmd}, os.Args[1:]...)
        rootCmd.SetArgs(args)
      }
      if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-08-15
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 2022-11-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      相关资源
      最近更新 更多