iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
Software Development

30 天學會做一個 CLI:打造人類與 AI 都友善的現代 CLI 應用系列 第 9

Human-friendly CLI 設計:命名、Help 與錯誤提示

  • 分享至 

  • xImage
  •  

CLI 運作在純文字的終端機環境中,不像 GUI 擁有按鈕、視覺邊框或選單點擊等提示。使用者第一次接觸工具時,無法透過視覺預覽介面,全靠輸入命令、查詢 --help 與閱讀錯誤訊息來理解工具的運作方式。如果不同命令間的語法缺乏一致性、--help 寫得像抽象規格書、輸入錯誤時程式只拋出一句 invalid argument,或是執行破壞性動作時缺乏安全預設值,開發節奏就會被反覆打斷。

良好的 CLI 設計不在於堆疊複雜功能,而是提供可類推、可引導且安全的文字介面體驗。接下來的 Human-friendly 與 Agent-friendly CLI 設計分為以下五個層面:

  • 命令命名、Help 與錯誤提示(本篇):建立可猜測的命令慣例、提供附帶實例的 Help、印出指引下一步的錯誤訊息,以及安全的預設行為。
  • 輸出美化與格式化(CLI 輸出:表格、顏色與進度):將 stdout 資料整理為對齊表格與狀態顏色,並在 stderr 呈現進度動畫與診斷訊息。
  • 輸入引導與 Shell 互動(CLI 互動:Shell 自動完成、選單與表單):透過 Shell Tab 自動完成、鍵盤選單與步驟表單降低輸入門檻。
  • 持續互動機制(CLI 的持續互動:REPL 模式):在維持連線與狀態的情境下提供即時互動迴圈。
  • 自動化與 AI 介面(Agent-friendly CLI 設計:非互動路徑與結構化輸出):為腳本與 AI Agent 提供無干擾的結構化資料路徑。

在這五個層面中,文字介面的起點就是使用者輸入的第一個命令。如果命令名稱與 Flag 無法直覺推測,後續的表格輸出或選單互動再漂亮,使用者也會因為敲不對命令而無法開始。

讓命令與 Flag 能從既有習慣猜出

良好的命名設計能讓使用者直接從日常工具(如 gitdockerkubectl)的經驗類推語法,不必每次切換命令都重新翻閱文件。如果一套 CLI 採用非標準或缺乏一致性的命名結構,就會打斷使用者的操作習慣。

主流 CLI 的命名語序主要分為兩種結構。第一種是 gh 採用的「資源在前、動作在後」:

gh issue list
gh pr list
gh release create
gh workflow run

kubectl 則採用「動作在前、資源在後」的結構:

kubectl get pods
kubectl get services
kubectl delete deployment api

這兩種結構各自成立,重點在於同一套 CLI 工具必須全篇保持統一。如果 mycli env list 採用了「資源在前、動作在後」,其他子命令就應寫成 mycli deploy list,不要交替改成 mycli list deploy。結構統一後,使用者只要學會一組命令,就能順暢推測出其他功能的語法。

每個動作固定使用同一個詞彙

代表相同動作的動詞如果在不同子命令中混用 listshow-allget-all,使用者就必須額外記憶每個資源選用了哪個詞彙。選定 list 後,所有列舉資源的命令都應統一稱為 list;刪除動作也應在 deleteremove 之間固定使用一個。

命令名稱要精準反映影響範圍。真正會清理資源的命令用 delete;僅變更狀態、將資源設為停用的動作用 disablearchive,避免使用者從名稱誤判破壞程度。

用程式結構維持語法一致

當多個資源包含相同動作時,可以透過 Go 語言的工廠函式建立 Cobra 命令,確保語意與說明格式集中管理:

// 所有資源的列舉命令都統一使用 list。
func newListCmd(resource string, run func(cmd *cobra.Command, args []string) error) *cobra.Command {
	return &cobra.Command{
		Use:   "list",
		Short: fmt.Sprintf("列出所有 %s", resource),
		RunE:  run,
	}
}

envCmd.AddCommand(newListCmd("env", runListEnvs))
deployCmd.AddCommand(newListCmd("deploy", runListDeploys))

修改說明文字或命令結構時,調整該工廠函式即可套用到所有子命令。寫入類命令的共用 Flag 也可以集中註冊:

func addWriteFlags(cmd *cobra.Command) {
	cmd.Flags().Bool("dry-run", false, "只顯示將執行的動作,不實際執行")
	cmd.Flags().BoolP("force", "f", false, "跳過確認提示")
}

沿用常見的 Flag 慣例

Flag 名稱應沿用慣例。使用者看到 --output/-o--force/-f--verbose/-v--dry-run,就能直接推斷用途。同一功能在所有子命令中也必須使用相同的 Flag 名稱,例如輸出格式統一用 --output,不要部分命令寫成 --format

短 Flag(Short Flag)適合在終端機中快速手動輸入,長 Flag(Long Flag)適合寫入腳本以維護可讀性。常用 Flag 可以同時提供長短兩種形式:

cmd.Flags().StringP("output", "o", "table", "輸出格式:table、json")

撰寫附帶可執行範例的 Help 訊息

--help 是終端機內最重要的說明文件。一個好的 Help 訊息應由三層結構組成:

  • Short:單句摘要,顯示於父命令的 Help 清單中。
  • Long:詳細說明,交代命令預設行為、資源來源與執行限制。
  • Example:可複製執行的具體命令,示範常見操作情境。

撰寫 Example 時,應填入可執行的具體數值,不要寫成 <environment><project> 這類抽象的代碼名稱。帶有真實值的範例能讓使用者複製後直接在終端機中測試與執行:

var deployCreateCmd = &cobra.Command{
	Use:   "create",
	Short: "建立一次部署",
	Long:  "將目前目錄的專案部署到指定環境,未指定環境時使用設定檔中的 default_env。",
	Example: `  # 部署到預設環境
  mycli deploy create

  # 部署到 staging 並跳過測試
  mycli deploy create --env staging --skip-tests`,
	RunE: runDeployCreate,
}

當使用者執行 mycli deploy create --help 時,終端機呈現的畫面如下:

將目前目錄的專案部署到指定環境,未指定環境時使用設定檔中的 default_env。

Usage:
  mycli deploy create [flags]

Examples:
  # 部署到預設環境
  mycli deploy create

  # 部署到 staging 並跳過測試
  mycli deploy create --env staging --skip-tests

Flags:
  -e, --env string   目標部署環境 (預設為設定檔中的 default_env)
  -h, --help         顯示 create 的說明訊息
      --skip-tests   跳過單元測試與整合測試

這份輸出同時包含了短說明、預設值來源、可複製的命令範例與可用的 Flag,使用者不必離開終端機去查閱線上網頁即可完成操作。

提供包含修復步驟與建議的錯誤提示

當命令執行失敗時,僅印出 config not foundinvalid argument 只是在宣佈失敗,沒有提供修正方向。好的錯誤訊息應明確包含三個要素:失敗的操作、相關的位置或輸入值,以及使用者接下來可以採取的具體修復步驟。

以找不到設定檔為例,錯誤訊息應標示查詢的路徑與建立設定檔的初始化命令:

$ mycli deploy create
Error: 找不到設定檔(預設路徑:~/.mycli/config.yaml)

請執行以下命令建立初始設定檔:

  mycli init

當參數驗證失敗時,訊息應一併列出可用的有效值與正確語法,免去使用者再次手動輸入 --help 的過程:

$ mycli env list --output yaml
Error: 不支援輸出格式 "yaml"

可用的輸出格式:table、json
正確語法範例:

  mycli env list --output json

命令拼錯時的自動建議機制

當使用者打錯子命令時,Cobra 預設會透過編輯距離(Levenshtein distance)算法比對已註冊的命令清單,並印出最相似的名稱建議:

$ mycli deplyo create
Error: unknown command "deplyo" for "mycli"

Did you mean this?
        deploy

在演算法運作上,Cobra 計算輸入字串與合法的子命令之間的編輯距離(即插入、刪除或替換字元所需的最小次數)。cobra.Command 提供了兩個屬性供控制這項行為:

  • DisableSuggestions(預設為 false):設定為 true 時停用拼字建議。
  • SuggestionsMinimumDistance(預設為 2):設定允許的最大編輯距離。預設值 2 代表當輸入字串與合法命令的差異在 2 個字元以內時才會觸發 Did you mean this? 提示。
var rootCmd = &cobra.Command{
	Use:                        "mycli",
	DisableSuggestions:         false,
	SuggestionsMinimumDistance: 2,
}

建立安全、可覆寫且看得見的預設行為

預設值能大幅減少日常操作所需的輸入量。例如 mycli logs 預設顯示最近 20 筆日誌,使用者平常直接執行即可;需要調閱更多歷史紀錄時,再用 --limit 擴充數量:

# 預設顯示最近 20 筆日誌
mycli logs

# 顯示最近 100 筆日誌
mycli logs --limit 100

設計預設值時,必須遵守以下三條原則:

  • 非破壞性安全原則:預設行為絕對不能對資料造成不可逆的變更。刪除資料、覆寫設定或變更生產環境(Production)的操作,必須要求明確的參數或確認提示。
  • 優先序覆寫原則:設定值的評估順序必須嚴格保持為「Flag > 環境變數 > 設定檔 > 內建預設值」。評估邏輯在所有子命令中保持一致,使用者才不會對參數來源產生混淆。
  • 視覺透明原則:生效的預設值必須能被觀察。Flag 的預設值要明確標示在 --help 中;執行破壞性變更時,透過 --dry-run Flag 提前列出目標環境、資源名稱與即將執行的動作。
$ mycli deploy create --env prod --dry-run
[DRY-RUN] 即將部署至環境: prod
[DRY-RUN] 目標資源: api-server
[DRY-RUN] 執行動作: 更新 image 為 registry.example.com/api:v1.2.0
[DRY-RUN] 提示: 此操作未實際執行。若要執行部署,請移除 --dry-run Flag。

可預測的命名慣例、隨手可查且帶有範例的 --help、包含修復建議的錯誤提示,以及安全的預設行為,共同建立了 CLI 在終端機文字介面中的第一道防線。

完成命令介面與基礎互動設計後,下一篇我們接著介紹 stdout 的視覺呈現與 stderr 的動態反饋。


上一篇
Flag、環境變數與設定檔
下一篇
Human-friendly CLI 輸出:表格、顏色與進度
系列文
30 天學會做一個 CLI:打造人類與 AI 都友善的現代 CLI 應用11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言