一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - 在 Golang 中使用 Cobra 創建 CLI 應用

在 Golang 中使用 Cobra 創建 CLI 應用

2022-01-26 11:30吱吱吱 (piperck) XD Golang

這篇文章主要介紹了在 Golang 中使用 Cobra 創建 CLI 應用,來看下 Cobra 的使用,這里我們使用的 go1.13.3 版本,使用 Go Modules 來進行包管理,需要的朋友可以參考下

雖然現在我們使用的大多數軟件都是可視化的,很容易上手,但是這并不代表 CLI(命令行)應用就沒有用武之地了,特別是對于開發人員來說,還是會經常和 CLI 應用打交道。而 Golang 就非常適合用來構建 CLI 應用,下面我們就將來介紹如何在 Golang 中構建一個 CLI 應用。

對于開發人員來說平時可能就需要使用到很多 CLI 工具,比如 npm、node、go、python、docker、kubectl 等等,因為這些工具非常小巧、沒有依賴性、非常適合系統管理或者一些自動化任務等等。

我們這里選擇使用 Golang 里面非常有名的Cobra庫來進行 CLI 工具的開發。Cobra 是一個功能強大的現代化 CLI 應用程序庫,有很多知名的 Go 項目使用 Cobra 進行構建,比如:Kubernetes、Docker、Hugo 等等

概念

Cobra 是構建在命令、參數和標識符之上的:

  • Commands表示執行動作
  • Args就是執行參數
  • Flags是這些動作的標識符

基本的執行命令如下所示:

?
1
2
3
$ APPNAME Command Args --Flags
# 或者
$ APPNAME Command --Flags Args

比如我們平時使用的一些命令行工具:

?
1
2
3
4
git clone URL -bare
go get -u URL
npm install package –save
kubectl get pods -n kube-system -l app=cobra

示例

下面我們來看下 Cobra 的使用,這里我們使用的 go1.13.3 版本,使用 Go Modules 來進行包管理,如果對這部分知識點不熟悉的,可以查看前面我們的文章Go Modules 基本使用(視頻)了解。

新建一個名為my-calc的目錄作為項目目錄,然后初始化 modules:

?
1
2
3
4
$ mkdir my-calc && cd my-calc
# 如果 go modules 默認沒有開啟,需要執行 export GO111MODULE=on 開啟
$ go mod init my-calc
go: creating new go.mod: module my-calc

初始化完成后可以看到項目根目錄下面多了一個go.mod的文件,現在我們還沒有安裝cobra庫,執行下面的命令進行安裝:

?
1
2
3
# 強烈推薦配置該環境變量
$ export GOPROXY=https://goproxy.cn
$ go get -u github.com/spf13/cobra/cobra

安裝成功后,現在我們可以使用cobra init命令來初始化 CLI 應用的腳手架:

?
1
2
3
$ cobra init --pkg-name my-calc
Your Cobra applicaton is ready at
/Users/ych/devs/workspace/youdianzhishi/course/my-calc

需要注意的是新版本的 cobra 庫需要提供一個--pkg-name參數來進行初始化,也就是指定上面我們初始化的模塊名稱即可。上面的 init 命令就會創建出一個最基本的 CLI 應用項目:

?
1
2
3
4
5
6
7
8
9
10
$ tree .
.
├── LICENSE
├── cmd
│   └── root.go
├── go.mod
├── go.sum
└── main.go
 
1 directory, 5 files

其中main.go是 CLI 應用的入口,在main.go里面調用好了cmd/root.go下面的Execute函數:

?
1
2
3
4
5
6
7
8
// main.go
package main
 
import "my-calc/cmd"
 
func main() {
    cmd.Execute()
}

然后我們再來看下cmd/root.go文件。

rootCmd

root(根)命令是 CLI 工具的最基本的命令,比如對于我們前面使用的go get URL,其中go就是 root 命令,而get就是go這個根命令的子命令,而在root.go中就直接使用了 cobra 命令來初始化rootCmd結構,CLI 中的其他所有命令都將是rootCmd這個根命令的子命令了。

這里我們將cmd/root.go里面的rootCmd變量內部的注釋去掉,并在Run函數里面加上一句fmt.Println("Hello Cobra CLI")

?
1
2
3
4
5
6
7
8
9
10
11
12
13
var rootCmd = &cobra.Command{
    Use:   "my-calc",
    Short: "A brief description of your application",
    Long: `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.`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Hello Cobra CLI")
    },
}

這個時候我們在項目根目錄下面執行如下命令進行構建:

?
1
$ go build -o my-calc

該命令會在項目根目錄下生成一個名為my-calc的二進制文件,直接執行這個二進制文件可以看到如下所示的輸出信息:

$ ./my-calc
Hello Cobra CLI

init

我們知道init函數是 Golang 中初始化包的時候第一個調用的函數。在cmd/root.go中我們可以看到init函數中調用了cobra.OnInitialize(initConfig),也就是每當執行或者調用命令的時候,它都會先執行init函數中的所有函數,然后再執行execute方法。該初始化可用于加載配置文件或用于構造函數等等,這完全依賴于我們應用的實際情況。

在初始化函數里面cobra.OnInitialize(initConfig)調用了initConfig這個函數,所有,當rootCmd的執行方法RUN: func運行的時候,rootCmd根命令就會首先運行initConfig函數,當所有的初始化函數執行完成后,才會執行rootCmdRUN: func執行函數。

我們可以在initConfig函數里面添加一些 Debug 信息:

?
1
2
3
4
func initConfig() {
    fmt.Println("I'm inside initConfig function in cmd/root.go")
    ...
}

然后同樣重新構建一次再執行:

?
1
2
3
4
$ go build -o my-calc
$ ./my-calc
I'm inside initConfig function in cmd/root.go
Hello Cobra CLI

可以看到是首先運行的是initConfig函數里面的信息,然后才是真正的執行函數里面的內容。

為了搞清楚整個 CLI 執行的流程,我們在main.go里面也添加一些 Debug 信息:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// cmd/root.go
func init() {
    fmt.Println("I'm inside init function in cmd/root.go")
    cobra.OnInitialize(initConfig)
    ...
}
 
func initConfig() {
    fmt.Println("I'm inside initConfig function in cmd/root.go")
    ...
}
 
// main.go
func main() {
     fmt.Println("I'm inside main function in main.go")
     cmd.Execute()
}

然后同樣重新構建一次再執行:

?
1
2
3
4
5
6
$ go build -o my-calc
$ ./my-calc
I'm inside init function in cmd/root.go
I'm inside main function in main.go
I'm inside initConfig function in cmd/root.go
Hello Cobra CLI

根據上面的日志信息我們就可以了解到 CLI 命令的流程了。

init函數最后處理的就是flags了,Flags就類似于命令的標識符,我們可以把他們看成是某種條件操作,在 Cobra 中提供了兩種類型的標識符:Persistent FlagsLocal Flags

  • Persistent Flags: 該標志可用于為其分配的命令以及該命令的所有子命令。
  • Local Flags: 該標志只能用于分配給它的命令。

initConfig

該函數主要用于在 home 目錄下面設置一個名為.my-calc的配置文件,如果該文件存在則會使用這個配置文件。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// cmd/root.go
// initConfig 讀取配置文件和環境變量
func initConfig() {
    if cfgFile != "" {
        // 使用 flag 標志中傳遞的配置文件
        viper.SetConfigFile(cfgFile)
    } else {
        // 獲取 Home 目錄
        home, err := homedir.Dir()
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
        // 在 Home 目錄下面查找名為 ".my-calc" 的配置文件
        viper.AddConfigPath(home)
        viper.SetConfigName(".my-calc")
    }
    // 讀取匹配的環境變量
    viper.AutomaticEnv()
    // 如果有配置文件,則讀取它
    if err := viper.ReadInConfig(); err == nil {
        fmt.Println("Using config file:", viper.ConfigFileUsed())
    }
}

viper是一個非常優秀的用于解決配置文件的 Golang 庫,它可以從 JSON、TOML、YAML、HCL、envfile 以及 Java properties 配置文件中讀取信息,功能非常強大,而且不僅僅是讀取配置這么簡單,了解更多相關信息可以查看 Git 倉庫相關介紹:https://github.com/spf13/viper

現在我們可以去掉前面我們添加的一些打印語句,我們已經創建了一個my-calc命令作為rootCmd命令,執行該根命令會打印Hello Cobra CLI信息,接下來為我們的 CLI 應用添加一些其他的命令。

添加數據

在項目根目錄下面創建一個名為add的命令,Cobra添加一個新的命令的方式為:cobra add <commandName>,所以我們這里直接這樣執行:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cobra add add
add created at /Users/ych/devs/workspace/youdianzhishi/course/my-calc
$ tree .
.
├── LICENSE
├── cmd
│   ├── add.go
│   └── root.go
├── go.mod
├── go.sum
├── main.go
└── my-calc
 
1 directory, 7 files

現在我們可以看到cmd/root.go文件中新增了一個add.go的文件,我們仔細觀察可以發現該文件和cmd/root.go比較類似。首先是聲明了一個名為addCmd的結構體變量,類型為*cobra.Command指針類型,*cobra.Command有一個RUN函數,帶有*cobra.Command指針和一個字符串切片參數。

然后在init函數中進行初始化,初始化后,將其添加到rootCmd根命令中rootCmd.AddCommand(addCmd),所以我們可以把addCmd看成是rootCmd的子命令。

同樣現在重新構建應用再執行:

?
1
2
3
4
5
$ go build -o my-calc
$ ./my-calc
Hello Cobra CLI
$ ./my-calc add
add called

可以看到add命令可以正常運行了,接下來我們來讓改命令支持添加一些數字,我們知道在RUN函數中是用戶字符串 slice 來作為參數的,所以要支持添加數字,我們首先需要將字符串轉換為 int 類型,返回返回計算結果。在cmd/add.go文件中添加一個名為intAdd的函數,定義如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// cmd/add.go
func intAdd(args []string) {
    var sum int
    // 循環 args 參數,循環的第一個值為 args 的索引,這里我們不需要,所以用 _ 忽略掉
    for _, ival := range args {
        // 將 string 轉換成 int 類型
        temp, err := strconv.Atoi(ival)
        if err != nil {
            panic(err)
        }
        sum = sum + temp
    }
    fmt.Printf("Addition of numbers %s is %d\n", args, sum)
}

然后在addCmd變量中,更新RUN函數,移除默認的打印信息,調用上面聲明的addInt函數:

?
1
2
3
4
// addCmd
Run: func(cmd *cobra.Command, args []string) {
    intAdd(args)
},

然后重新構建應用執行如下所示的命令:

?
1
2
3
4
5
6
$ go build -o my-calc
$ ./my-calc
Hello Cobra CLI
# 注意參數之間的空格
$ ./my-calc add 1 2 3
Addition of numbers [1 2 3] is 6

由于RUN函數中的args參數是一個字符串切片,所以我們可以傳遞任意數量的參數,但是確有一個缺陷,就是只能進行整數計算,不能計算小數,比如我們執行如下的計算就會直接 panic 了:

?
1
2
3
4
5
6
$ ./my-calc add 1 2 3.5
panic: strconv.Atoi: parsing "3.5": invalid syntax
 
goroutine 1 [running]:
my-calc/cmd.intAdd(0xc0000a5890, 0x3, 0x3)
......

因為在intAdd函數里面,我們只是將字符串轉換成了 int,而不是 float32/64 類型,所以我們可以為addCmd命令添加一個flag標識符,通過該標識符來幫助 CLI 確定它是 int 計算還是 float 計算。

cmd/add.go文件的init函數內部,我們創建一個 Bool 類型的本地標識符,命名成float,簡寫成f,默認值為 false。這個默認值是非常重要的,意思就是即使沒有在命令行中調用 flag 標識符,該標識符的值就將為 false。

?
1
2
3
4
5
// cmd/add.go
func init() {
    rootCmd.AddCommand(addCmd)
    addCmd.Flags().BoolP("float", "f", false, "Add Floating Numbers")
}

然后創建一個floatAdd的函數:

?
1
2
3
4
5
6
7
8
9
10
11
12
func floatAdd(args []string) {
    var sum float64
    for _, fval := range args {
        // 將字符串轉換成 float64 類型
        temp, err := strconv.ParseFloat(fval, 64)
        if err != nil {
            panic(err)
        }
        sum = sum + temp
    }
    fmt.Printf("Sum of floating numbers %s is %f\n", args, sum)
}

該函數和上面的intAdd函數幾乎是相同的,除了是將字符串轉換成 float64 類型。然后在addCmdRUN函數中,我們根據傳入的標識符來判斷到底應該是調用intAdd還是floatAdd,如果傳遞了--float或者-f標志,就將會調用floatAdd函數。

?
1
2
3
4
5
6
7
8
9
10
11
// cmd/add.go
// addCmd
Run: func(cmd *cobra.Command, args []string) {
    // 獲取 float 標識符的值,默認為 false
    fstatus, _ := cmd.Flags().GetBool("float")
    if fstatus { // 如果為 true,則調用 floatAdd 函數
        floatAdd(args)
    } else {
        intAdd(args)
    }
},

現在重新編譯構建 CLI 應用,按照如下方式執行:

?
1
2
3
4
5
6
7
$ go build -o my-calc
$ ./my-calc add 1 2 3
Addition of numbers [1 2 3] is 6
$ ./my-calc add 1 2 3.5 -f
Sum of floating numbers [1 2 3.5] is 6.500000
$./my-calc add 1 2 3.5 --float
Sum of floating numbers [1 2 3.5] is 6.500000

然后接下來我們在給addCmd添加一些子命令來擴展它。

添加偶數

同樣在項目根目錄下執行如下命令添加一個名為even的命令:

?
1
2
$ cobra add even
even created at /Users/ych/devs/workspace/youdianzhishi/course/my-calc

和上面一樣會在root目錄下面新增一個名為even.go的文件,修改該文件中的init函數,將rootCmd修改為addCmd,因為我們是為addCmd添加子命令:

?
1
2
3
4
// cmd/even.go
func init() {
    addCmd.AddCommand(evenCmd)
}

然后更新evenCmd結構體參數的RUN函數:

?
1
2
3
4
5
6
7
8
9
10
11
// cmd/even.go
Run: func(cmd *cobra.Command, args []string) {
    var evenSum int
    for _, ival := range args {
        temp, _ := strconv.Atoi(ival)
        if temp%2 == 0 {
            evenSum = evenSum + temp
        }
    }
    fmt.Printf("The even addition of %s is %d\n", args, evenSum)
},

首先將字符串轉換成整數,然后判斷如果是偶數才進行累加。然后重新編譯構建應用:

?
1
2
3
$ go build -o my-calc
$ ./my-calc add even 1 2 3 4 5 6
The even addition of [1 2 3 4 5 6] is 12

my-calc是我們的根命令,addrootCmd的子命令,even優勢addCmd的子命令,所以按照上面的方式調用??梢杂猛瑯拥姆绞皆偃ヌ砑右粋€奇數相加的子命令。

到這里我們就在 Golang 里面使用Cobra創建了一個簡單的 CLI 應用。本文的內容雖然比較簡單,但是是我們了解學習Cobra基礎的一個很好的入門方式,后續我們也可以嘗試添加一些更加復雜的使用案例。

Reference:

https://www.qikqiak.com/post/create-cli-app-with-cobra在 Golang 中使用 Cobra 創建 CLI 應用

https://cobra.dev cobra docs

到此這篇關于在 Golang 中使用 Cobra 創建 CLI 應用的文章就介紹到這了,更多相關Golang創建 CLI 應用內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/piperck/p/15762355.html

延伸 · 閱讀

精彩推薦
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
主站蜘蛛池模板: 4438全国最大成人网视频 | 欧美╳bbbb| 男女肉粗暴进来下面好紧 | 精品卡1卡2卡三卡免费视频 | 欧美理论片手机在线观看片免费 | 黄蓉h系列 | 日韩中文在线 | 亚洲国产精品嫩草影院永久 | 亚洲视频国产精品 | 性趣味商品推荐 | 国产精品不卡高清在线观看 | 麻豆网站视频国产在线观看 | 国产精品天天看特色大片不卡 | 亚洲不卡视频在线观看 | 久久黄色小视频 | porno18hd老师 | 国内精品91东航翘臀女神在线 | 国产日韩精品一区二区 | 国产伊人网 | 天天操天天做 | 香蕉91xj.cc| 星空无限传媒视频在线观看视频 | 香蕉人人超人人超碰超国产 | 成年男女免费视频观看性 | 色综合久久综精品 | 国产日韩欧美视频 | 99re免费在线视频 | 美女扒开两腿露出尿口的视频 | 免费观看在线永久免费xx视频 | 国内精品视频一区二区三区八戒 | 国产专区亚洲欧美另类在线 | 日韩毛片在线 | 性欧美sexvideo另类 | 亚洲国产日韩成人综合天堂 | 日本无遮挡亲吻膜下面免费 | 亚洲青草 | 18国产精品白浆在线观看免费 | 嗯啊视频在线 | 双性总裁(h) | 国产欧美又粗又猛又爽老 | 天天综合天天色 |