如何用cobra-cli实现中缀命令(如myapp <arg1> to <arg2>)?
实现中缀命令格式的解决方案
你要的myapp <arg1> to <arg2>这种中缀命令格式完全可以用cobra-cli实现,不需要定制开发,下面提供两种可行方案:
方案一:利用TraverseChildren特性保留子命令结构
cobra默认会在主命令满足参数要求后停止解析子命令,但开启TraverseChildren选项后,会继续遍历并匹配后续的子命令,刚好适配你的场景。具体调整如下:
- 修改主命令配置:去掉主命令的
Run函数(避免提前执行逻辑终止流程),添加TraverseChildren: true,确保主命令接收第一个参数后继续解析子命令。 - 确保子命令被添加到主命令:在
init函数中调用rootCmd.AddCommand(toCmd),让cobra能识别"to"子命令。 - 在子命令中获取主命令参数:通过
cmd.Parent().Args拿到主命令的第一个参数,结合子命令自身的参数完成逻辑。
修改后的完整代码示例:
var ( Version string // This will be set from main.go verbose bool ) var rootCmd = &cobra.Command{ Use: "commandlijn <station1>", Short: "A brief description of your application", Long: ``, Args: cobra.MinimumNArgs(1), TraverseChildren: true, // 关键:允许主命令参数后继续解析子命令 // 移除原Run函数,主命令仅作为参数入口 } var toCmd = &cobra.Command{ Use: "to <station2>", Short: "Finds connections between two stations", Long: `The 'to' command allows you to find train connections between two stations. You need to specify the departure station and the arrival station.`, Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { stationFrom := cmd.Parent().Args[0] // 从主命令获取出发站 stationTo := args[0] // 获取到达站 fmt.Printf("查询从 %s 到 %s 的线路\n", stationFrom, stationTo) // 执行你的业务逻辑 }, } func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } func init() { // 添加to子命令到主命令 rootCmd.AddCommand(toCmd) // 原有的flag配置保留 rootCmd.Flags().BoolP("version", "V", false, "Print the version number and exit") rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output") rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") }
方案二:将"to"作为关键字在主命令中解析
如果不需要保留子命令结构,可以直接在主命令中把"to"当作参数分隔关键字,一次性解析两个参数:
var ( Version string verbose bool ) var rootCmd = &cobra.Command{ Use: "commandlijn <station1> to <station2>", Short: "A brief description of your application", Long: ``, Run: func(cmd *cobra.Command, args []string) { // 查找"to"的位置,验证参数格式 toIdx := -1 for i, arg := range args { if arg == "to" { toIdx = i break } } if toIdx == -1 || toIdx == 0 || toIdx == len(args)-1 { fmt.Println("错误:请使用格式 commandlijn <出发站> to <到达站>") os.Exit(1) } stationFrom := args[0] stationTo := args[toIdx+1] fmt.Printf("查询从 %s 到 %s 的线路\n", stationFrom, stationTo) // 执行你的业务逻辑 }, } // Execute和init函数保持原有逻辑,注意不需要to子命令 func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } } func init() { rootCmd.Flags().BoolP("version", "V", false, "Print the version number and exit") rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output") rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") }
两种方案对比
- 方案一保留了cobra的子命令结构,适合后续扩展更多子命令的场景,帮助信息也会自动包含"to"命令的说明。
- 方案二更简洁,直接适配中缀格式,不需要额外的子命令配置,适合逻辑简单的场景。
内容的提问来源于stack exchange,提问作者Erlich Bachman
相关产品推荐
相关产品推荐

