rootCmd.Execute() 必须作为 main() 最后一行执行,否则命令树不会加载;Cobra 命令树惰性加载,仅 Execute() 调用时才解析命令行、匹配子命令、挂载 flag;rootCmd 需为包级变量,AddCommand() 必须在 Execute() 前调用。

rootCmd.Execute() 必须作为 main() 最后一行执行,否则命令树根本不会加载——这不是初始化顺序问题,是执行驱动机制缺失。
为什么 rootCmd 定义了却报 command not found
根本原因不是没调 cobra.Init(),而是没触发 rootCmd.Execute()。Cobra 的命令树是惰性加载的:只有 Execute() 被调用时,才解析命令行、匹配子命令、挂载 flag。没这一步,cmd.AddCommand(subCmd) 就像往空盒子里塞纸条,没人打开就永远看不见。
-
rootCmd必须是包级变量(不能在函数里 new 后返回),且由cmd/root.go初始化 - 所有
AddCommand()调用必须发生在Execute()之前,推荐放在init()或main()开头 - 如果用了
cobra-cli add xxx生成子命令,检查生成的cmd/xxx.go是否被 import 到cmd/root.go中(常见漏点)
flag.StringP() 参数顺序写反会 panic
flag.StringP("port", "p", "8080", "listen port") 看似简单,但第二个参数是短选项名,必须是单字符;写成 flag.StringP("port", "8080", "p", ...) 会导致运行时报 invalid shorthand format。
- 正确顺序固定:
LongName、Shorthand、DefaultValue、Usage - 短选项不能是空字符串或多个字母(如
"pt"),否则解析失败或静默忽略 - 若多个 flag 共享同一短选项(比如两个
-v),后注册的会覆盖前一个,可用cmd.Flags().Lookup("v").Usage检查是否冲突
子命令 flag 不生效?大概率继承搞错了
默认情况下,子命令会继承 rootCmd.PersistentFlags(),但不会自动继承 rootCmd.Flags()。反过来,子命令自己的 Flags() 也不会被父命令看到——这是设计,不是 bug。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
- 全局 flag(如
--config、--verbose)必须注册到rootCmd.PersistentFlags() - 仅对
serve有效的--port,就得在serveCmd.Flags()里注册,而不是塞进 root - 验证方法:运行
mytool serve --help,看--port是否出现;若只在mytool --help里有,说明注册位置错了
RunE 不只是多返回 error,它决定了错误能不能被看见
用 Run 时,一旦内部 panic 或调用 log.Fatal,进程立刻退出,用户只看到空白或 exit status 1;而 RunE 把 error 交给 Cobra 统一处理,自动加前缀、支持 --debug 显示 stack trace、兼容 shell 补全。
立即学习“go语言免费学习笔记(深入)”;
- 所有业务逻辑必须收在
RunE里,返回error,不要fmt.Println + os.Exit(1) - 避免在
init()里读配置或连 DB——那里 panic 无法被捕获,直接卡死启动 - 若必须 recover,写在
RunE开头:defer func() { if r := recover(); r != nil { cmd.PrintErrln("panic:", r) } }()
text/tabwriter 在不同平台对宽字符和制表符的渲染差异。别急着改 Cobra,先试 go build -ldflags="-s -w" 编译再验证输出。

















