← Validator | Go-Micro →

Cobra - Go 命令行框架

Cobra 是 Go 最流行的命令行框架,被 kubectl、docker、github-cli 等知名项目使用。它提供了丰富的子命令、标志、参数等功能,是开发 CLI 工具的首选。

快速开始

📝 基础命令行

package main

import (
    "fmt"
    "os"
    "github.com/spf13/cobra"
)

var (
    name    string
    verbose bool
)

// root 命令
var rootCmd = &cobra.Command{
    Use:   "myapp",
    Short: "My CLI Application",
    Long:  `A longer description of my CLI application.`,
    Run: func(cmd *cobra.Command, args []string) {
        if verbose {
            fmt.Println("Verbose mode enabled")
        }
        fmt.Printf("Hello, %s!\n", name)
    },
}

func init() {
    // 定义标志
    rootCmd.Flags().StringVarP(&name, "name", "n", "World", "Your name")
    rootCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output")
}

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

子命令

📝 添加子命令

package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

// server 命令
var serverCmd = &cobra.Command{
    Use:   "server",
    Short: "Start the server",
    Run: func(cmd *cobra.Command, args []string) {
        port, _ := cmd.Flags().GetInt("port")
        fmt.Printf("Starting server on port %d...\n", port)
    },
}

// server start 子命令
var serverStartCmd = &cobra.Command{
    Use:   "start",
    Short: "Start server",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Server started")
    },
}

// server stop 子命令
var serverStopCmd = &cobra.Command{
    Use:   "stop",
    Short: "Stop server",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Server stopped")
    },
}

func init() {
    // 添加子命令
    rootCmd.AddCommand(serverCmd)
    serverCmd.AddCommand(serverStartCmd)
    serverCmd.AddCommand(serverStopCmd)
    
    // 添加标志
    serverCmd.Flags().IntP("port", "p", 8080, "Server port")
}

// 使用:
// myapp server start --port 9000
// myapp server stop

标志类型

📝 各种标志类型

func init() {
    // String 类型
    rootCmd.Flags().String("config", "", "Config file")
    rootCmd.Flags().StringP("output", "o", "", "Output file")
    
    // Int 类型
    rootCmd.Flags().Int("count", 1, "Number of items")
    rootCmd.Flags().IntP("port", "p", 8080, "Port number")
    
    // Bool 类型
    rootCmd.Flags().Bool("debug", false, "Debug mode")
    rootCmd.Flags().BoolP("verbose", "v", false, "Verbose")
    
    // Float 类型
    rootCmd.Flags().Float64("timeout", 30.0, "Timeout in seconds")
    
    // String 数组
    rootCmd.Flags().StringSlice("tags", []string{}, "Tags")
    
    // Int 数组
    rootCmd.Flags().IntSlice("ports", []int{}, "Ports")
    
    // 获取标志值
    var config string
    rootCmd.Flags().StringVar(&config, "config", "", "Config file")
    
    // 在 Run 中获取
    func(cmd *cobra.Command, args []string) {
        config, _ := cmd.Flags().GetString("config")
        port, _ := cmd.Flags().GetInt("port")
        verbose, _ := cmd.Flags().GetBool("verbose")
    }
}

参数验证

📝 参数验证器

var echoCmd = &cobra.Command{
    Use:   "echo [string]",
    Short: "Echo the input",
    // 参数验证
    Args: cobra.ExactArgs(1), // 必须 1 个参数
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Echo: " + args[0])
    },
}

// 其他验证器
var cmds = []*cobra.Command{
    {
        Use:  "no-args",
        Args: cobra.NoArgs, // 不能有参数
    },
    {
        Use:  "min-args",
        Args: cobra.MinimumNArgs(2), // 至少 2 个参数
    },
    {
        Use:  "max-args",
        Args: cobra.MaximumNArgs(3), // 最多 3 个参数
    },
    {
        Use:  "exact-args",
        Args: cobra.ExactArgs(2), // 精确 2 个参数
    },
    {
        Use:  "range-args",
        Args: cobra.RangeArgs(1, 3), // 1 到 3 个参数
    },
    {
        Use:  "only-files",
        Args: cobra.OnlyValidArgs, // 只能是 ValidArgs 中的值
        ValidArgs: []string{"bash", "zsh", "fish"},
    },
}

持久标志

📝 持久标志 (子命令共享)

func init() {
    // 持久标志:所有子命令都可使用
    rootCmd.PersistentFlags().StringP(
        "config", "c", "", "Config file path",
    )
    
    // 普通标志:仅当前命令可用
    rootCmd.Flags().BoolP(
        "verbose", "v", false, "Verbose output",
    )
}

// 使用:
// myapp --config /etc/app.conf server start -v
// config 对 server 和 start 都可用
// verbose 仅对 server 可用

完整示例

📝 完整 CLI 应用

package main

import (
    "fmt"
    "os"
    "github.com/spf13/cobra"
)

var (
    cfgFile string
    verbose bool
)

var rootCmd = &cobra.Command{
    Use:   "todo",
    Short: "Todo CLI Application",
    Long:  `A command line todo list manager.`,
}

// add 命令
var addCmd = &cobra.Command{
    Use:   "add [task]",
    Short: "Add a new task",
    Args:  cobra.MinimumNArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        task := args[0]
        fmt.Printf("Added task: %s\n", task)
    },
}

// list 命令
var listCmd = &cobra.Command{
    Use:   "list",
    Short: "List all tasks",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Listing tasks...")
    },
}

// complete 命令
var completeCmd = &cobra.Command{
    Use:   "complete [task-id]",
    Short: "Mark task as complete",
    Args:  cobra.ExactArgs(1),
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Printf("Completed task: %s\n", args[0])
    },
}

func init() {
    // 持久标志
    rootCmd.PersistentFlags().StringVarP(
        &cfgFile, "config", "c", "", "Config file",
    )
    rootCmd.PersistentFlags().BoolVarP(
        &verbose, "verbose", "v", false, "Verbose output",
    )
    
    // 添加子命令
    rootCmd.AddCommand(addCmd)
    rootCmd.AddCommand(listCmd)
    rootCmd.AddCommand(completeCmd)
    
    // add 命令标志
    addCmd.Flags().StringP("priority", "p", "medium", "Priority level")
}

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

最佳实践

✅ Cobra 使用建议

  • 命令结构: 使用子命令组织功能
  • 持久标志: 全局配置使用 PersistentFlags
  • 参数验证: 使用 Args 验证器
  • 帮助信息: 提供清晰的 Short/Long 描述
  • 错误处理: Execute 返回错误要处理

📖 延伸阅读