命令行工具
命令行工具
Cobra 是 Go 命令行应用框架,支持嵌套子命令、POSIX Flag、帮助信息、命令建议和 Shell 自动补全。
go get github.com/spf13/cobra@latest
根命令
每个命令都是一个 cobra.Command。程序入口只负责执行根命令:
var rootCmd = &cobra.Command{
Use: "app",
Short: "Example command-line application",
SilenceUsage: true,
SilenceErrors: true,
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
SilenceUsage 避免业务执行失败时输出整段帮助,SilenceErrors 让入口统一决定错误格式和退出码。
子命令与参数
var userGetCmd = &cobra.Command{
Use: "get <id>",
Short: "Get a user",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
user, err := service.GetUser(cmd.Context(), args[0])
if err != nil {
return fmt.Errorf("get user: %w", err)
}
return json.NewEncoder(cmd.OutOrStdout()).Encode(user)
},
}
func init() {
userCmd := &cobra.Command{Use: "user", Short: "Manage users"}
userCmd.AddCommand(userGetCmd)
rootCmd.AddCommand(userCmd)
}
执行方式为:
app user get user-1
优先使用返回 error 的 RunE,不要在命令内部调用 log.Fatal 或 os.Exit,否则难以测试和统一处理错误。
Flag
局部 Flag 只属于当前命令,Persistent Flag 会被所有子命令继承:
var output string
var configFile string
func init() {
userGetCmd.Flags().StringVarP(&output, "output", "o", "table",
"output format: table or json")
rootCmd.PersistentFlags().StringVar(&configFile, "config", "",
"path to configuration file")
}
必需 Flag 应显式标记,并处理返回的错误:
if err := userGetCmd.MarkFlagRequired("output"); err != nil {
panic(err)
}
配置较多时可以把 Cobra 的 Flag 绑定到 Viper,但业务代码仍应接收解析后的配置结构体,而不是直接依赖 Cobra 或 Viper。
Shell 补全
Cobra 可以生成 Bash、Zsh、Fish 和 PowerShell 补全脚本:
completionCmd := &cobra.Command{
Use: "completion [bash|zsh|fish|powershell]",
Args: cobra.ExactValidArgs(1),
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
RunE: func(cmd *cobra.Command, args []string) error {
switch args[0] {
case "bash":
return rootCmd.GenBashCompletion(cmd.OutOrStdout())
case "zsh":
return rootCmd.GenZshCompletion(cmd.OutOrStdout())
case "fish":
return rootCmd.GenFishCompletion(cmd.OutOrStdout(), true)
default:
return rootCmd.GenPowerShellCompletion(cmd.OutOrStdout())
}
},
}
测试
使用可替换的输入输出和 Context 测试命令,不需要启动子进程:
buffer := new(bytes.Buffer)
rootCmd.SetOut(buffer)
rootCmd.SetErr(buffer)
rootCmd.SetArgs([]string{"user", "get", "user-1", "--output", "json"})
err := rootCmd.ExecuteContext(context.Background())
测试之间不要复用已经执行过且包含可变全局 Flag 的命令树。较大的 CLI 可以用构造函数创建新的根命令,并把 Service 作为参数注入。
代码生成器
官方 cobra-cli 可以初始化项目并生成命令文件:
go install github.com/spf13/cobra-cli@latest
cobra-cli init
cobra-cli add user
生成器只是脚手架,并不是运行 Cobra 应用的必要依赖。项目结构稳定后,也可以直接手写 cobra.Command。