
golang-spf13-cobra
熱門使用 spf13/cobra 的 Golang CLI 指令樹函式庫 — cobra.Command、RunE 與 Run 的比較、PersistentPreRunE 鉤子鏈、Args 驗證器(NoArgs、ExactArgs、MatchAll、自訂)、持久旗標與本地旗標、指令群組、ValidArgsFunction、RegisterFlagCompletionFunc、ShellCompDirective、使用說明/幫助模板自訂、man-page 與 markdown 文件產生,以及使用 SetArgs/SetOut/SetErr 進行測試。適用於使用或採用 spf13/cobra 時,或當程式碼庫匯入 `github.com/spf13/cobra` 時。如需與 cobra 搭配的設定分層,請參閱 `samber/cc-skills-golang@golang-spf13-viper` 技能。如需一般 CLI 架構(專案佈局、退出碼、訊號處理、I/O 模式),請參閱 `samber/cc-skills-golang@golang-cli` 技能。
使用 spf13/cobra 的 Golang CLI 指令樹函式庫 — cobra.Command、RunE 與 Run 的比較、PersistentPreRunE 鉤子鏈、Args 驗證器(NoArgs、ExactArgs、MatchAll、自訂)、持久旗標與本地旗標、指令群組、ValidArgsFunction、RegisterFlagCompletionFunc、ShellCompDirective、使用說明/幫助模板自訂、man-page 與 markdown 文件產生,以及使用 SetArgs/SetOut/SetErr 進行測試。適用於使用或採用 spf13/cobra 時,或當程式碼庫匯入 `github.com/spf13/cobra` 時。如需與 cobra 搭配的設定分層,請參閱 `samber/cc-skills-golang@golang-spf13-viper` 技能。如需一般 CLI 架構(專案佈局、退出碼、訊號處理、I/O 模式),請參閱 `samber/cc-skills-golang@golang-cli` 技能。
角色: 你是一位 Go CLI 工程師,負責建構讓 Unix shell 使用者感到自然的指令樹。你優先設計使用者面向的介面,然後將行為掛接到適當的鉤子中。
模式:
- 建構 — 從頭建立新的 CLI:依序遵循指令樹設定、鉤子接線和旗標章節。
- 擴充 — 為現有 CLI 新增子指令、旗標或自動完成:先讀取當前指令樹,然後套用與現有結構一致的變更。
- 審查 — 稽核現有 CLI:檢查常見錯誤表格,驗證
RunE使用方式、OutOrStdout()、鉤子鏈順序和參數驗證。
在 Go 中使用 spf13/cobra 建立 CLI 指令樹
Cobra 是 Go CLI 應用程式的業界標準。它提供指令/子指令樹、旗標解析(透過 pflag)、參數驗證、shell 自動完成產生和文件產生。它不處理設定分層——那是 viper 的工作。
官方資源:
此技能並非詳盡無遺。請參閱函式庫文件和程式碼範例以獲取更多資訊。Context7 可作為可發現性平台提供協助。如需 Go 套件文件、版本、符號和已知漏洞,→ 請參閱 samber/cc-skills-golang@golang-pkg-go-dev 技能。
go get github.com/spf13/cobra@latest
Cobra 與 viper 的比較
這些函式庫執行根本不同的功能,可以獨立使用。
| 關注點 | cobra | viper |
|---|---|---|
| 擁有 | 指令樹、旗標、參數驗證、自動完成 | 設定值解析 |
| 面向使用者? | 是 — 子指令、旗標、幫助文字 | 否 — 純粹是鍵值解析器 |
| 沒有對方? | 是 — 僅需旗標的 CLI 只需要 cobra | 是 — 讀取 YAML + 環境變數的守護程式只需要 viper |
| 整合介面 | 透過 BindPFlag 將 pflag.Flag 傳遞給 viper |
將 cobra 旗標視為最高優先順序層 |
單獨使用 cobra:當你的二進位檔接受旗標和參數,但不需要設定檔或環境變數解析時。單獨使用 viper:當你有一個長時間執行的服務從 YAML + 環境變數讀取設定,且沒有 CLI 子指令時。兩者都需要時則一起使用——在根指令的 PersistentPreRunE 中進行綁定。
→ 請參閱 samber/cc-skills-golang@golang-spf13-viper 技能以了解 viper 端的整合。
指令樹
每個 cobra CLI 都有一個根指令,加上零個或多個透過 AddCommand 註冊的子指令。根指令名稱即為二進位檔名稱。
var rootCmd = &cobra.Command{
Use: "myapp",
Short: "一行摘要",
SilenceUsage: true, // ✓ 防止每次錯誤都顯示完整使用說明
SilenceErrors: true, // ✓ 讓你可以控制錯誤輸出格式
}
使用 AddGroup 在幫助輸出中為子指令加上標籤——在引用這些群組的 AddCommand 呼叫之前註冊群組;cobra 不會事後指派群組。
Run* 系列
Cobra 指令有五個按順序執行的執行鉤子:
PersistentPreRunE → PreRunE → RunE → PostRunE → PersistentPostRunE
始終使用 *E 變體——非 E 形式無法回傳錯誤。關鍵規則:
- 根指令上的
PersistentPreRunE在每個子指令之前執行——用於設定初始化和權限檢查。 - 子指令的
PersistentPreRunE完全取代父指令的——如果需要兩者,請在子指令中明確呼叫父指令。 PostRunE僅在RunE成功後執行。
有關完整的生命週期和繼承規則,請參閱 commands-and-args.md。
Args 驗證器
Cobra 在 RunE 執行之前驗證位置參數。永遠不要在 RunE 內部撰寫 len(args) 檢查——這會繞過 cobra 的標準錯誤訊息和參數計數追蹤。
內建驗證器:NoArgs、ExactArgs(n)、MinimumNArgs(n)、MaximumNArgs(n)、RangeArgs(min,max)、OnlyValidArgs、ExactValidArgs(n)。使用 MatchAll(v1, v2) 組合。自訂驗證器:func(cmd *cobra.Command, args []string) error。
有關完整的驗證器集合、範例和 MatchAll 模式,請參閱 commands-and-args.md。
旗標入門
Cobra 將旗標解析委派給 pflag。持久旗標(PersistentFlags())由所有子指令繼承;本地旗標(Flags())僅適用於宣告該旗標的指令。
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "設定檔路徑") // 所有子指令繼承
serveCmd.Flags().IntVar(&port, "port", 8080, "監聽埠號") // 僅 serveCmd 本地
serveCmd.MarkFlagRequired("port")
serveCmd.MarkFlagsMutuallyExclusive("json", "yaml")
有關 pflag 類型、自訂旗標值、旗標群組和 viper 綁定,請參閱 flags.md。
自動完成入門
Cobra 會自動產生 shell 自動完成。透過以下方式擴充:
ValidArgs []string— 靜態位置參數自動完成。ValidArgsFunction— 動態:func(cmd, args, toComplete string) ([]string, ShellCompDirective)。回傳ShellCompDirectiveNoFileComp以抑制檔案回退。RegisterFlagCompletionFunc(name, fn)— 旗標值自動完成。
有關 ShellCompDirective 值、註解和測試,請參閱 completions.md。
測試指令
透過程式化執行指令來測試。永遠不要直接在指令處理程式中使用 os.Stdout / os.Stderr——請使用 cmd.OutOrStdout() / cmd.ErrOrStderr(),以便測試可以重新導向輸出。
func TestServeCmd(t *testing.T) {
buf := new(bytes.Buffer)
rootCmd.SetOut(buf)
rootCmd.SetArgs([]string{"serve", "--port", "9090"})
require.NoError(t, rootCmd.Execute())
assert.Contains(t, buf.String(), "正在監聽 :9090")
}
Cobra 會在多次 Execute() 呼叫之間累積旗標狀態——請為每個測試建立一個全新的指令樹。有關隔離模式、黃金檔案和測試自動完成,請參閱 testing.md。
最佳實務
- 始終使用
RunE,永遠不要使用Run—Run無法回傳錯誤;唯一的逃脫方式是os.Exit或 panic,這會繞過 defer。 - 將設定初始化放在
PersistentPreRunE中 — 它在每個子指令之前執行;這是進行 viper 綁定和權限檢查的正確位置。 - 使用
Args驗證位置參數,而不是在RunE內部 —Args提供 cobra 的標準錯誤訊息;MatchAll可組合驗證器。 - 所有輸出都使用
cmd.OutOrStdout()/cmd.ErrOrStderr()— 直接寫入os.Stdout無法被測試捕捉。 - 每個測試重新建立指令樹 — cobra 在同一個實例上跨
Execute()呼叫累積旗標狀態。
常見錯誤
| 錯誤 | 失敗原因 | 修正方式 |
|---|---|---|
使用 Run 而非 RunE |
無法回傳錯誤 — 唯一逃脫是 os.Exit 或 panic,繞過 defer |
使用 RunE — 回傳錯誤,讓 cobra 處理退出 |
在 RunE 中撰寫 len(args) 檢查 |
繞過 cobra 的標準錯誤訊息("接受 1 個參數,收到 2 個") | 在指令上宣告 Args: cobra.ExactArgs(1) |
直接寫入 os.Stdout |
測試無法捕捉輸出 — 作業系統層級的檔案控制代碼無法重新導向 | 使用 cmd.OutOrStdout() / cmd.ErrOrStderr() |
子指令的 PersistentPreRunE 靜默丟棄父指令的 |
Cobra 不會串聯 — 子指令完全取代父指令的鉤子 | 在子指令的鉤子中呼叫 parent.PersistentPreRunE(cmd, args) |
| 跨測試重複使用根指令 | Cobra 累積旗標狀態;第二次 Execute() 會看到第一次的旗標 |
每個測試建立一個全新的指令樹 |
延伸閱讀
- commands-and-args.md — 完整的 PreRun*/PostRun* 鏈、每個 Args 驗證器、PersistentPreRunE 繼承規則
- flags.md — pflag 類型、必要/互斥/單一必要群組、自訂值類型、viper 綁定
- completions.md — ShellCompDirective 集合、基於註解的自動完成、測試自動完成
- generators.md — man page、markdown、YAML、RST 文件產生;
cobra-cli腳手架工具 - testing.md — 隔離模式、黃金檔案、測試自動完成、表格驅動指令測試
交叉參考
- → 請參閱
samber/cc-skills-golang@golang-cli技能以了解一般 CLI 架構 — 專案佈局、退出碼、訊號處理、I/O 模式 - → 請參閱
samber/cc-skills-golang@golang-spf13-viper技能以了解與 cobra 搭配的設定分層(旗標 → 環境變數 → 檔案 → 預設優先順序) - → 請參閱
samber/cc-skills-golang@golang-testing技能以了解一般 Go 測試模式
如果你遇到 spf13/cobra 的錯誤或非預期行為,請在 https://github.com/spf13/cobra/issues 開啟議題。





