Cobra — CLI 框架
Cobra 是 Go 最流行的 CLI 框架,Kubernetes、Hugo、GitHub CLI 都用它构建。
安装
bash
go get -u github.com/spf13/cobra@latest
# 可选:安装代码生成器
go install github.com/spf13/cobra-cli@latest快速开始
go
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "myapp",
Short: "我的命令行工具",
Long: `一个功能强大的命令行工具,用于处理各种任务。`,
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}子命令
go
// cmd/serve.go
var serveCmd = &cobra.Command{
Use: "serve",
Short: "启动 HTTP 服务器",
Long: `启动一个 HTTP 服务器,监听指定端口。`,
RunE: func(cmd *cobra.Command, args []string) error {
port, _ := cmd.Flags().GetInt("port")
fmt.Printf("服务器启动在端口 %d\n", port)
return startServer(port)
},
}
func init() {
rootCmd.AddCommand(serveCmd)
serveCmd.Flags().IntP("port", "p", 8080, "监听端口")
serveCmd.Flags().String("host", "0.0.0.0", "监听地址")
}
// cmd/user.go — 嵌套子命令
var userCmd = &cobra.Command{
Use: "user",
Short: "用户管理",
}
var userCreateCmd = &cobra.Command{
Use: "create [name]",
Short: "创建用户",
Args: cobra.ExactArgs(1), // 必须有且只有 1 个参数
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
email, _ := cmd.Flags().GetString("email")
return createUser(name, email)
},
}
var userListCmd = &cobra.Command{
Use: "list",
Short: "列出所有用户",
RunE: func(cmd *cobra.Command, args []string) error {
page, _ := cmd.Flags().GetInt("page")
return listUsers(page)
},
}
func init() {
rootCmd.AddCommand(userCmd)
userCmd.AddCommand(userCreateCmd, userListCmd)
userCreateCmd.Flags().StringP("email", "e", "", "用户邮箱(必填)")
userCreateCmd.MarkFlagRequired("email")
userListCmd.Flags().IntP("page", "p", 1, "页码")
}
// 使用:
// myapp user create Alice --email alice@example.com
// myapp user list --page 2Flags 类型
go
// 持久 Flag(对所有子命令生效)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "配置文件路径")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "详细输出")
// 本地 Flag(只对当前命令生效)
serveCmd.Flags().IntP("port", "p", 8080, "端口")
serveCmd.Flags().StringSlice("tags", []string{}, "标签列表")
serveCmd.Flags().Duration("timeout", 30*time.Second, "超时时间")
// 必填 Flag
serveCmd.MarkFlagRequired("port")
// 互斥 Flag
serveCmd.MarkFlagsMutuallyExclusive("json", "yaml")
// 绑定到变量
var port int
serveCmd.Flags().IntVarP(&port, "port", "p", 8080, "端口")与 Viper 集成
go
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "配置文件")
rootCmd.PersistentFlags().String("db-url", "", "数据库连接串")
// 将 flag 绑定到 viper
viper.BindPFlag("database.url", rootCmd.PersistentFlags().Lookup("db-url"))
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("$HOME/.myapp")
}
viper.AutomaticEnv() // 自动读取环境变量
if err := viper.ReadInConfig(); err == nil {
fmt.Println("使用配置文件:", viper.ConfigFileUsed())
}
}完整 CLI 项目结构
mycli/
├── cmd/
│ ├── root.go # 根命令
│ ├── serve.go # serve 子命令
│ ├── user.go # user 子命令组
│ └── version.go # version 子命令
├── internal/
│ └── ...
├── main.go
└── go.modgo
// main.go
package main
import "mycli/cmd"
func main() {
cmd.Execute()
}
// cmd/root.go
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "mycli",
Short: "我的 CLI 工具",
// PersistentPreRunE 在所有子命令前执行
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return initializeApp()
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// cmd/version.go
var versionCmd = &cobra.Command{
Use: "version",
Short: "显示版本信息",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("mycli version %s (commit: %s)\n", Version, Commit)
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}最佳实践
- 使用
RunE而非Run,可以返回错误 - 用
cobra-cli add <command>快速生成命令文件 - 配合 Viper 实现配置文件 + 环境变量 + 命令行参数三级覆盖
- 为每个命令写好
Short和Long描述,--help会自动生成