golang-cli

golang-cli

熱門

Golang CLI 應用程式開發。在建立、修改或審查 Go CLI 工具時使用,特別是針對指令結構、旗標處理、設定分層、版本嵌入、結束碼、I/O 模式、訊號處理、Shell 補全、引數驗證及 CLI 單元測試。當程式碼使用 cobra、viper 或 urfave/cli 時也會觸發。如需 cobra 特定 API → 請參閱 `samber/cc-skills-golang@golang-spf13-cobra` 技能;如需 viper 設定分層 → 請參閱 `samber/cc-skills-golang@golang-spf13-viper` 技能。

2261星標
150分支
更新於 2026/6/6
SKILL.md
readonlyread-only
name
golang-cli
description

Golang CLI 應用程式開發。在建立、修改或審查 Go CLI 工具時使用,特別是針對指令結構、旗標處理、設定分層、版本嵌入、結束碼、I/O 模式、訊號處理、Shell 補全、引數驗證及 CLI 單元測試。當程式碼使用 cobra、viper 或 urfave/cli 時也會觸發。如需 cobra 特定 API → 請參閱 `samber/cc-skills-golang@golang-spf13-cobra` 技能;如需 viper 設定分層 → 請參閱 `samber/cc-skills-golang@golang-spf13-viper` 技能。

角色: 你是一位 Go CLI 工程師。你打造的工具要讓 Unix Shell 感覺很原生 — 可組合、可腳本化,且在自動化環境下可預測。

模式:

  • 建置 — 從頭建立新的 CLI:依序遵循專案結構、根指令設定、旗標綁定及版本嵌入等章節。
  • 擴充 — 為現有 CLI 新增子指令、旗標或補全功能:先讀取現有指令樹,然後套用與現有結構一致的變更。
  • 審查 — 稽核現有 CLI 的正確性:檢查常見錯誤表,驗證 SilenceUsage/SilenceErrors、旗標與 Viper 的綁定、結束碼,以及 stdout/stderr 的規範。

Go CLI 最佳實務

使用 Cobra + Viper 作為 Go CLI 應用程式的預設技術棧。Cobra 提供指令/子指令/旗標結構,Viper 則處理來自檔案、環境變數及旗標的設定,並自動分層。這個組合驅動了 kubectl、docker、gh、hugo 及大多數生產環境的 Go CLI。

使用 Cobra 或 Viper 時,請參考該函式庫的官方文件及程式碼範例以取得最新的 API 簽章。

對於沒有子指令且旗標很少的簡單單一用途工具,使用標準函式庫的 flag 就已足夠。

快速參考

關注點 套件 / 工具
指令與旗標 github.com/spf13/cobra
設定 github.com/spf13/viper
旗標解析 github.com/spf13/pflag (透過 Cobra)
彩色輸出 github.com/fatih/color
表格輸出 github.com/olekukonko/tablewriter
互動式提示 github.com/charmbracelet/bubbletea
版本注入 go build -ldflags
發布 goreleaser

專案結構

將 CLI 指令組織在 cmd/myapp/ 目錄下,每個指令一個檔案。保持 main.go 最小化 — 它只呼叫 Execute()

myapp/
├── cmd/
│   └── myapp/
│       ├── main.go              # package main,只呼叫 Execute()
│       ├── root.go              # 根指令 + Viper 初始化
│       ├── serve.go             # "serve" 子指令
│       ├── migrate.go           # "migrate" 子指令
│       └── version.go           # "version" 子指令
├── go.mod
└── go.sum

main.go 應保持最小化 — 請參閱 assets/examples/main.go

根指令設定

根指令透過 PersistentPreRunE 初始化 Viper 設定並設定全域行為。請參閱 assets/examples/root.go

重點:

  • SilenceUsage: true 必須設定 — 防止在每次錯誤時都印出完整的使用說明
  • SilenceErrors: true 必須設定 — 讓你可以自行控制錯誤輸出格式
  • PersistentPreRunE 在每個子指令之前執行,因此設定總是已初始化
  • 日誌輸出到 stderr,一般輸出到 stdout

子指令

cmd/myapp/ 中建立個別檔案來新增子指令,並在 init() 中註冊它們。請參閱 assets/examples/serve.go 以取得完整的子指令範例,包含指令群組。

旗標

請參閱 assets/examples/flags.go 以取得所有旗標模式:

持久 vs 區域

  • 持久 旗標會被所有子指令繼承(例如 --config
  • 區域 旗標僅適用於定義它們的指令(例如 --port

必要旗標

使用 MarkFlagRequiredMarkFlagsMutuallyExclusiveMarkFlagsOneRequired 來設定旗標約束。

使用 RegisterFlagCompletionFunc 進行旗標驗證

為旗標值提供補全建議。

始終將旗標綁定到 Viper

這確保 viper.GetInt("port") 會回傳旗標值、環境變數 MYAPP_PORT 或設定檔值 — 以優先順序最高的為準。

引數驗證

Cobra 為位置引數提供了內建的驗證器。請參閱 assets/examples/args.go 以取得內建及自訂驗證的範例。

驗證器 描述
cobra.NoArgs 若提供任何引數則失敗
cobra.ExactArgs(n) 需要恰好 n 個引數
cobra.MinimumNArgs(n) 需要至少 n 個引數
cobra.MaximumNArgs(n) 最多允許 n 個引數
cobra.RangeArgs(min, max) 需要介於 min 和 max 之間
cobra.ExactValidArgs(n) 恰好 n 個引數,且必須在 ValidArgs 中

使用 Viper 進行設定

Viper 依以下順序解析設定值(優先順序由高到低):

  1. CLI 旗標(明確的使用者輸入)
  2. 環境變數(部署設定)
  3. 設定檔(持久設定)
  4. 預設值(在程式碼中設定)

請參閱 assets/examples/config.go 以取得完整的 Viper 整合範例,包含結構體解碼及設定檔監控。

設定檔範例 (.myapp.yaml)

port: 8080
host: localhost
log-level: info
database:
  dsn: postgres://localhost:5432/myapp
  max-conn: 25

透過上述設定,以下方式都是等效的:

  • 旗標:--port 9090
  • 環境變數:MYAPP_PORT=9090
  • 設定檔:port: 9090

版本與建置資訊

版本應在編譯時使用 ldflags 嵌入。請參閱 assets/examples/version.go 以取得版本指令及建置說明。

結束碼

結束碼必須遵循 Unix 慣例:

代碼 意義 使用時機
0 成功 操作正常完成
1 一般錯誤 執行時期失敗
2 使用錯誤 無效的旗標或引數
64-78 BSD sysexits 特定錯誤類別
126 無法執行 權限不足
127 找不到指令 缺少相依套件
128+N 訊號 N 被訊號終止(例如 130 = SIGINT)

請參閱 assets/examples/exit_codes.go 以取得將錯誤對應到結束碼的模式。

I/O 模式

請參閱 assets/examples/output.go 以取得所有 I/O 模式:

  • stdout vs stderr:絕不要將診斷輸出寫到 stdout — stdout 用於程式輸出(可 pipe),stderr 用於日誌/錯誤/診斷
  • 偵測 pipe vs 終端機:檢查 stdout 的 os.ModeCharDevice
  • 機器可讀輸出:支援 --output 旗標以輸出 table/json/plain 格式
  • 顏色:使用 fatih/color,它會在輸出不是終端機時自動停用顏色

訊號處理

訊號處理必須使用 signal.NotifyContext 來透過 context 傳播取消訊號。請參閱 assets/examples/signal.go 以取得優雅的 HTTP 伺服器關機範例。

Shell 補全

Cobra 會自動為 bash、zsh、fish 及 PowerShell 產生補全。請參閱 assets/examples/completion.go 以取得補全指令及自訂旗標/引數補全的範例。

測試 CLI 指令

透過程式化執行指令並擷取輸出來測試指令。請參閱 assets/examples/cli_test.go

在指令中使用 cmd.OutOrStdout()cmd.ErrOrStderr()(而非 os.Stdout / os.Stderr),以便在測試中擷取輸出。

常見錯誤

錯誤 修正
直接寫入 os.Stdout 測試無法擷取輸出。使用 cmd.OutOrStdout(),測試可將其重新導向到 buffer
RunE 內呼叫 os.Exit() Cobra 的錯誤處理、延遲函式及清理程式碼都不會執行。回傳錯誤,讓 main() 決定
未將旗標綁定到 Viper 旗標將無法透過環境變數/設定檔設定。為每個可設定的旗標呼叫 viper.BindPFlag
缺少 viper.SetEnvPrefix PORT 會與其他工具衝突。使用前綴(MYAPP_PORT)來為環境變數命名空間
將日誌輸出到 stdout Unix pipe 會串接 stdout — 日誌會破壞下一個程式的資料流。日誌應輸出到 stderr
每次錯誤都印出使用說明 每次錯誤都印出完整說明文字是噪音。設定 SilenceUsage: true,將完整使用說明保留給 --help
設定檔為必要 沒有設定檔的使用者會導致崩潰。忽略 viper.ConfigFileNotFoundError — 設定檔應為選用
未使用 PersistentPreRunE 設定初始化必須在任何子指令之前發生。使用根指令的 PersistentPreRunE
硬編碼版本字串 版本會與標籤不同步。在編譯時透過 ldflags 從 git 標籤注入
不支援 --output 格式 腳本無法解析人類可讀的輸出。加入 JSON/table/plain 格式供機器使用

相關技能

請參閱 samber/cc-skills-golang@golang-project-layoutsamber/cc-skills-golang@golang-dependency-injectionsamber/cc-skills-golang@golang-testingsamber/cc-skills-golang@golang-design-patterns 技能。