Go 用 cobra 构建企业级 CLI:子命令、flag 绑定与配置加载
test12026-10-190 次阅读
为什么手写 flag 不够
小工具用标准库 flag 包够用,但一旦要支持子命令(如 app serve / app migrate)、全局与局部 flag、自动 help 与补全,就得上 cobra。它是 Kubernetes、Hugo 等项目的 CLI 框架,约定清晰、扩展性强。
定义根命令与子命令
每个命令是一个 *cobra.Command,Run 里写逻辑。子命令用 AddCommand 挂到根上。
package cmd
import "github.com/spf13/cobra"
var rootCmd = &cobra.Command{
Use: "app",
Short: "业务管理命令行工具",
}
var serveCmd = &cobra.Command{
Use: "serve",
Short: "启动 HTTP 服务",
RunE: func(cmd *cobra.Command, args []string) error {
port, _ := cmd.Flags().GetInt("port")
return startServer(port)
},
}
func init() {
serveCmd.Flags().Int("port", 8080, "监听端口")
rootCmd.AddCommand(serveCmd)
}
func Execute() error { return rootCmd.Execute() }
用 viper 把 flag 与配置文件打通
cobra 的 flag 变化多,配合 viper 可以从环境变量、yaml 文件回填默认值,优先级是 flag > 环境 > 文件 > 代码默认。
func init() {
serveCmd.Flags().String("config", "", "配置文件路径")
serveCmd.PreRunE = func(cmd *cobra.Command, args []string) error {
cfgFile, _ := cmd.Flags().GetString("config")
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
return viper.ReadInConfig()
}
return nil
}
}
错误处理与退出码
用 RunE 返回 error,cobra 会自动打印并退出码非 0;需要自定义退出码时调用 os.Exit 并在 SilenceErrors 关掉默认输出。
var versionCmd = &cobra.Command{
Use: "version",
Short: "打印版本",
Run: func(cmd *cobra.Command, args []string) { fmt.Println("v1.4.0") },
}
func main() {
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}
落地要点
- 子命令放独立文件、在各自 init 里 AddCommand,避免根文件膨胀。
- 需要校验必填参数用 MarkFlagRequired,cobra 自动拦截并提示。
- 持久 flag(如 --verbose)挂在 PersistentFlags,对所有子命令生效。
- 发布前跑 app --help 和 app serve --help,确认 help 文案与默认值正确。
T
test1
文章作者
为什么手写 flag 不够 小工具用标准库 flag 包够用,但一旦要支持子命令(如 app serve / app...
- 分类
- 技术
- 发布时间
- 2026-10-19
- 字数
- 约 1673 字
- 阅读
- 0 次
