Golang:Cobra安裝與使用
引子
最近在做一個基於Golang的CLI程式,索性便將自己探索出來的經驗寫下與諸位分享,如果更好的方法也希望大家能告知,共同進步
Cobra安裝
大部分教程都是直接告訴我們,我們只需要在有go的環境下,輸入
$ go get -v github.com/spf13/cobra/cobra
便可以順順利利的安裝。然而,現實與理想還是有差距的。許多同學都因為某些被牆的連結而停在了某一步驟。解決方法當然是有的。
請在 $GOPATH/src/golang.org/x
目錄下用 git clone
下載 sys 和 text 專案,然後使用 go install github.com/spf13/cobra/cobra
$GOBIN
下出現了cobra 可執行程式。如果你沒有配置 $GOBIN
,那麼可以在$GOPATH/bin
下找到 cobra的可執行軟體。(這個方法適用於大部分出現類似問題的第三方包下載)
Cobra使用
生成專案檔案
cobra程式只能在GOPATH之下使用,所以首先你需要進入到GOPATH的src目錄之下,在該目錄下,輸入:
$GOPATH/src/$ cobra init demo
在你的當前目錄下,應該已經生成了一個demo資料夾:
demo
├── cmd
│ └── root.go
├── LICENSE
└── main.go
上述便是該資料夾的結構,我們可以進去該資料夾,執行:
$ go run main.go
應該會列印如下結果:
A longer description that spans multiple lines and likely contains examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
至此,我們的cobra專案便已經生成完畢
新增子命令
這裡我們先講述如何新增子命令,再說明如何新增引數。
實際操作其實cobra都能幫你完成,假設我們現在需要新增一個test引數,在專案資料夾下命令列輸入
../src/demo$ cobra add test
執行完成後,現在我們的demo結構應該是:
.
├── cmd
│ ├── root.go
│ └── test.go
├── LICENSE
└── main.go
可以看到,在cmd目錄下,已經生成了一個與我們命令同名的go檔案,你也許已經猜測到,與該命令有關的操作也正是在此處實現。現在執行這個子命令
$ go run main.go test
命令列將會列印輸出test called
那麼現在又有一個問題,如果我們想新增子命令下的子命令呢?
現在讓我們開啟test.go,你應該看到如下的檔案內容:
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// testCmd represents the test command
var testCmd = &cobra.Command{
Use: "test",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("test called")
},
}
func init() {
RootCmd.AddCommand(testCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// testCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// testCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
你會發現,在init中有一句 RootCmd.AddCommand(testCmd)
這個RootCmd是什麼?開啟root.go,你會發現RootCmd其實就是我們的根命令。我相信機智的同學已經猜出來我們新增子命令的子命令的方法了。現在讓我們在cmd目錄下新建testson.go檔案,把test.go的內容複製進去,並修改為如下內容:
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// testCmd represents the test command
var testsonCmd = &cobra.Command{
Use: "testson",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("testson called")
},
}
func init() {
testCmd.AddCommand(testsonCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// testCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// testCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
現在在命令列執行:
go run main.go test testson
當你看到testson called
,恭喜你,子命令新增成功!否則你應當檢查你的程式碼是否有誤。
新增引數
我相信從init函式中的註釋中,你已經得到了足夠多的資訊來自己操作新增flag,但我還是想要囉嗦兩句。首先是persistent引數,當你的引數作為persistent flag存在時,如註釋所言,在其所有的子命令之下該引數都是可見的。而local flag則只能在該命令呼叫時執行。可以做一個簡單的測試,在test.go的init函式中,新增如下內容:
testCmd.PersistentFlags().String("foo", "", "A help for foo")
testCmd.Flags().String("foolocal", "", "A help for foo")
現在在命令列 go run main.go test -h
得到如下結果:
../src/demo$ go run main.go test -h
A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
Usage:
demo test [flags]
demo test [command]
Available Commands:
testson A brief description of your command
Flags:
--foo string A help for foo
--foolocal string A help for foo
-h, --help help for test
Global Flags:
--config string config file (default is $HOME/.demo.yaml)
Use "demo test [command] --help" for more information about a command.
接著讓我們再執行 go run main.go test testson -h
../src/demo$ go run main.go test testson -h
A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
Usage:
demo test testson [flags]
Flags:
-h, --help help for testson
Global Flags:
--config string config file (default is $HOME/.demo.yaml)
--foo string A help for foo
可以發現在Gloabal Flags的變化。test作為root的子命令,仍然可以使用root的persistent flag-> config(可以檢視root.go),而testson作為test的子命令,不僅可以使用test的persistent flag-> fool, 也可以使用test父命令的persistent flag。從而我們可以直觀的看出persistent的作用範圍是該命令之後的所有子命令。接下來你可能會問,那flag支援什麼型別引數?答案是,請檢視官方文件
請注意,cmd.Flags().String()與 cmd.Flags().StringP()是不一樣的。假如我們在test.go的init下增加如下兩行:
testCmd.Flags().String("f", "", "test")
testCmd.Flags().StringP("aaa", "a", "", "test")
前者呼叫需要如下形式:
go run main.go test --f
後者有如下兩種形式呼叫:
go run main.go test --aaa
go run main.go test -a
另外可以額外告知你如何使用slice作為引數,如[]string:
testCmd.Flags().StringSliceP("arr","r", nil, "test arr")
呼叫該引數的方法為:
go run main.go test -r "a,b,c"
請不要鍵入多餘空格(除非確實需要鍵入),也不要使用空格替代逗號作為分割符
獲取引數值
在知道了如何設定引數後,我們的下一步當然便是需要在執行時獲取該引數的值。現在讓我們把注意力放到test.go的此部分:
var testCmd = &cobra.Command{
Use: "test",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("test called")
},
}
在給你講述如何獲取引數值之前,我希望你能先學習cobra.Command結構,相信我,這樣並不會浪費你的時間。如果你只希望知道如何獲取引數值,那麼也可以在以後再學習。
讓我們把注意力重新放到上面的程式碼上。我們也很容易可以猜測到Use,Short,Long三個引數的作用,這裡便不做闡述(你可以參照新增子命令的子命令的部分的輸出)。顯而易見,我們應該在Run
這裡來獲取引數並執行我們的命令功能。獲取引數其實也並不複雜。以testCmd.Flags().StringP("aaa", "a", "", "test")
此為例,我們可以在Run函式裡新增:
str := testCmd.Flags().GetString("aaa")
這樣便可以獲取到該引數的值了,其餘型別引數獲取也是同理。如 testCmd.Flags().GetStringSlice("arr")
,規律並不難見。
End
至此,你已經有了利用cobra構建一個cli程式的基本能力了。當然,更為複雜的方法在這裡並沒有介紹(因為我沒用到:)),你可以通過官方文件(推薦)或者他人文件來學習更為複雜的應用。