go使用spf13/cobra库

一、介绍

cobra是一个命令行程序库,其提供简单的接口来创建强大现代的CLI接口,可以用来编写命令行程序。同时,它也提供了一个脚手架, 用于生成基于 cobra 的应用程序框架。

二、概念

Cobra基于三个基本概念commands,arguments和flags。其中commands代表行为,arguments代表数值,flags代表对行为的改变。
基本模型如下:
APPNAME VERB NOUN --ADJECTIVE或者APPNAME COMMAND ARG --FLAG

例如:

# server是commands,port是flag
hugo server --port=1313

# clone是commands,URL是arguments,brae是flags
git clone URL --bare

Commands

Commands是应用的中心点,同样commands可以有子命令(children commands),其分别包含不同的行为。
Commands的结构体如下:

type Command struct {
    Use string // The one-line usage message.
    Short string // The short description shown in the 'help' output.
    Long string // The long message shown in the 'help <this-command>' output.
    Run func(cmd *Command, args []string) // Run runs the command.
}

Flags

Flags用来改变commands的行为。其完全支持POSIX命令行模式和Go的flag包。这里的flag使用的是spf13/pflag包,具体可以参考Golang之使用Flag和Pflag.

cobra 中选项分为Flags,一种是永久选项,定义它的命令和其子命令都可以使用。通过给根命令添加一个选项定义全局选项。 另一种是本地选项,只能在定义它的命令中使用。

与flag一样,存储选项的变量也需要提前定义好:

var Verbose bool
var Source string

设置永久Flags:

rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")

设置本地Flags:

localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")

Arguments

Leagacy arg validation有以下几类:

  • NoArgs: 如果包含任何位置参数,命令报错
  • ArbitraryArgs: 命令接受任何参数
  • OnlyValidArgs: 如果有位置参数不在ValidArgs中,命令报错
  • MinimumArgs(init): 如果参数数目少于N个后,命令行报错
  • MaximumArgs(init): 如果参数数目多余N个后,命令行报错
  • ExactArgs(init): 如果参数数目不是N个话,命令行报错
  • RangeArgs(min, max): 如果参数数目不在范围(min, max)中,命令行报错

如: 命令行参数不少于1个

var helloCmd = &cobra.Command {
    Use: "hello",
    Short: "hello 子命令.",
    Long: "这是一个Hello 子命令",
    Args:  cobra.MinimumNArgs(1),
    Run: runHello,
}

自字义Arguments判断

var cmd = &cobra.Command{
  Use: "hello",
  Short: "hello",
  Args: func(cmd *cobra.Command, args []string) error {
    if len(args) < 1 {
      return errors.New("requires at least one arg")
    }
    if myapp.IsValidColor(args[0]) {
      return nil
    }
    return fmt.Errorf("invalid color specified: %s", args[0])
  },
  Run: func(cmd *cobra.Command, args []string) {
    fmt.Println("Hello, World!")
  },
}

三、快速使用

安装

go get github.com/spf13/cobra/cobra

导入

import  "github.com/spf13/cobra"

文件结构

 ▾ cjapp/
    ▾ cmd/
        hello.go
        root.go
        version.go
      go.mod
      main.go

go.mod

module zngw

go 1.14

require github.com/spf13/cobra v1.2.1

root.go

package cmd

import (
    "fmt"
    "github.com/spf13/cobra"
)

var rootCmd = &cobra.Command {
    Use: "zngw",
    Short: "这是 cobra 测试程序主入口",
    Long: `这是 cobra 测试程序主入口, 无参数启动时进入`,
    Run: runRoot,
}

func Execute() {
    if err := rootCmd.Execute(); err != nil {
        panic(err)
    }
}

func runRoot(cmd *cobra.Command, args []string)  {
    fmt.Printf("execute %s args:%v \n", cmd.Name(), args)
    // TODO 这里处理无参数启动时程序处理
}

hello.go

package cmd

import (
    "fmt"
    "github.com/spf13/cobra"
)

var helloCmd = &cobra.Command {
    Use: "hello",
    Short: "hello 子命令.",
    Long: "这是一个Hello 子命令",
    Args:  cobra.MinimumNArgs(1),
    Run: runHello,
}

func init() {
    rootCmd.AddCommand(helloCmd)
}

func runHello(cmd *cobra.Command, args []string)  {
    // TODO 这里处理hello子命令

    fmt.Println("Hello ", args[0])
}

version.go

package cmd

import (
    "fmt"
    "github.com/spf13/cobra"
)

var versionCmd = &cobra.Command {
    Use: "version",
    Short: "version 子命令.",
    Long: "这是一个version 子命令",
    Run: runVersion,
}

func init() {
    rootCmd.AddCommand(versionCmd)
}

func runVersion(cmd *cobra.Command, args []string)  {
    // TODO 这里处理version子命令

    fmt.Println("version is 1.0.0")
}

main.go

package main

import (
    "zngw/cmd"
    )

func main()  {
    cmd.Execute()
}

测试

进入工程目录,直接使用go build编译,编译后的可执行程序为zngw.exe

  • 自带-h参数,生成帮助信息
E:\55\cobra>zngw -h
这是 cobra 测试程序主入口, 无参数启动时进入

Usage:
  zngw [flags]
  zngw [command]

Available Commands:
  completion  generate the autocompletion script for the specified shell
  hello       hello 子命令.
  help        Help about any command
  version     version 子命令.

Flags:
  -h, --help   help for zngw

Use "zngw [command] --help" for more information about a command.
  • 测试子命令
E:\55\zngw>zngw
execute zngw args:[]

E:\55\zngw>zngw hello guoke
Hello  guoke

E:\55\zngw>zngw version
version is 1.0.0
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容