如果你要寫 Command line 工具,又想在各平台 (像是 MacOS, Windows 或 Linux) 上執行,這時候 Golang 就是您最好的選擇。在 Reddit 讀到一篇 Command line 工具比較介紹,這篇最主要講到兩個 CLI 工具,一個是 urfave/cli,另一個是 spf13/cobra,這兩個工具其實都非常好用,後者是去年加入 Google Golang 團隊的 spf13 所開發,該作者加入 Google 後呢,非常的忙,但是強者他同事有幫忙繼續維護 cobra 專案,兩個 CLI 工具各自都有有大型專案使用 urfave/cli 有 docker/libcompose, docker/machine, Drone, Gitea, Gogs 等,而後者 spf13/cobra 則有 docker, docker/distribution, etcd 等。本篇筆者會介紹 urfave/cli 該如何使用?
用 Golang 內建 flag 套件
其實 Golang 本身就有支援 Command line 功能,只要 importflag
就可以直接使用了
package main import ( "flag" "fmt" "os" ) func main() { var showVersion bool flag.BoolVar(&showVersion, "version", false, "Print version information.") flag.BoolVar(&showVersion, "v", false, "Print version information.") flag.Parse() // Show version and exit if showVersion { fmt.Println("Version 1.0.0") os.Exit(0) } }存檔成
main.go
,執行 go build -o main
就可以產生 main 執行檔,最後可以直接下 ./main -v
畫面就會顯示 Version 1.0.0
。但是如果 flag 非常多,寫起來就會相當長,也不支援讀取 Environment 環境變數,這時候我們可以透過 urfave/cli 來簡化此流程。上面的範例可以在底下連結找到
用 Golang flag 寫 Command Line
使用 urfave/cli 套件
底下是一個簡單範例,可以從 command line 讀取使用者帳號密碼package main import ( "fmt" "os" "github.com/urfave/cli" ) type ( // Config information. Config struct { username string password string } ) var config Config func main() { app := cli.NewApp() app.Name = "Example" app.Usage = "Example" app.Action = run app.Flags = []cli.Flag{ cli.StringFlag{ Name: "username,u", Usage: "user account", }, cli.StringFlag{ Name: "password,p", Usage: "user password", }, } app.Run(os.Args) } func run(c *cli.Context) error { config = Config{ username: c.String("username"), password: c.String("password"), } return exec() } func exec() error { fmt.Println("username:", config.username) fmt.Println("password:", config.password) return nil }從上面例子可以發現從
Name
就可以定義 Flag 名稱,用逗號分格,在命令列就可以使用 -u
或 --username
,也會自動幫忙產生完整的 help 畫面
支援環境變數
在 Golang 可以快速的將執行檔打包成 Docker ImageFROM centurylink/ca-certs ADD main / ENTRYPOINT ["/main"]在 Dockerfile 內使用參數可以透過
CMD
會變成底下
FROM centurylink/ca-certs ADD main / ENTRYPOINT ["/main"] CMD ["-u", "appleboy"]這樣非常麻煩,這時候就要讓 CLI 也支援環境變數,將
cli.StringFlag
改成如下
app.Flags = []cli.Flag{ cli.StringFlag{ Name: "username,u", Usage: "user account", + EnvVar: "DOCKER_USERNAME", }, cli.StringFlag{ Name: "password,p", Usage: "user password", + EnvVar: "DOCKER_PASSWORD", }, }直接在命令列執行
DOCKER_USERNAME=appleboy ./main
,則就會抓到 DOCKER_USERNAME
環境變數,在 Docker 指令就可以補上 -e
參數來實現變數傳遞:
$ docker run -e DOCKER_USERNAME=appleboy appleboy/cli
結論
把 Golang 執行檔包進去 Docker Image,就可以再任意環境內執行,如果你不想使用 Docker Image 也沒關係,Golang 支援跨平台編譯,底下是支援 Windows, Linux, MacOS 編譯參數GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/main-linux GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o bin/main.exe GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -o bin/main-darwin自從學了 Golang,讓用 Windows 工作的同事,也可以享用 Golang 的好處。上述範例檔案可以參考底下連結