0
点赞
收藏
分享

微信扫一扫

go语言命令行程序(CLI)开发工具小记

go语言命令行程序(CLI)开发工具小记_框架

Go语言领域,命令行程序占据比较重要的位置。因此,命令行程序的快速开发及工具选择就成为一个不可忽视的问题。本文简要总结使用Go语言开发命令行程序中常用的几个框架。

一、Cobra

Cobra 是关于 golang 的一个命令行解析库,用它能够快速创建功能强大的 cli 应用程序和命令行工具。

cobra既是一个用于创建强大现代CLI应用程序的库,也是一个生成应用程序和命令文件的程序。cobra被用在很多go语言的项目中,比如 Kubernetes、Docker、Istio、ETCD、Hugo、Github CLI等等。

hugo:号称速度最快的静态站点生成器。

我们平常用到命令:git commit -m “message”,docker containter start 等都可以用 cobra 来实现。

  • Cobra 官网:https://cobra.dev/
  • github地址:https://github.com/spf13/cobra

功能特性介绍

  • 很多子命令的CLIS: 比如 app server、app fetch 等
  • 支持嵌套子命令(sub-command)
  • 轻松完成应用程序和命令的创建:cobra init appname 和 cobra add cmdname
  • 为应用程序生成 man 手册
  • 全局、本地和级联 flag
  • 为 shell 程序完成自动提示(bash,zsh,fish, powershell etc.)
  • 支持命令行别名,可以帮助你更容易更改内容而不破坏他们
  • 灵活定义自己的help、usage信息
  • 可选集成 viper 配置管理工具库

Cobra命令结构说明

Cobra 命令结构由3部分组成:

commands、arguments 和 flags

commands:

命令行,代表行为动作,要执行的一个动作。每个命令还可以包含子命令,分为:rootCmd 和 subCmd。程序中具体对象是 cobra.Command{},这个是根命令;子命令(subCmd)用 rootCmd.AddCommand() 添加,子命令通常也会单独存一个文件,并通过一个全局变量让 rootCmd 可以 add 它。

arguments:

命令行参数,通常是 []string 表示。

flags:

命令行选项。对 command 进一步的控制。通常用一短横 - 或者两短横 -- 标识,程序中读取存储在变量中。

cobra 命令行格式:

APPNAME VERB NOUN --ADJECTIVE

APPNEM COMMAND ARG --FLAG

例子说明:

# server代表command,port代表flag

hugo server --port=1313

# clone代表command,URL代表argument,bare代表flag

git clone URL --bare



二、go语言内置flag库

Flag库是golang自带的命令行参数库。可以通过 -name abc的方式 或者-name=abc 的方式来给命令行参数name传入 abc这个值。

1. 简单使用命令行参数的情况

  1. 需要特别注意 一定不要忘记调用 flag.Parse() 否则你的参数都是默认值。
  2. 另外需要注意StringVar 中第一个参数一定是变量的指针 这样才能将解析到的值添加到变量中。

package main

import (
   "flag"
   "fmt"
)

// 适用于最简单的 只有一组命令行参数的情况

// 带有等号的格式
// eg: go run main.go -name=ikun -id=29238 -male

// 不带有等号的格式
// eg: go run main.go -name ikun -id 29238 -male
func main() {
   var name string
   var studentId int
   var isMale bool

   // 定义 flag.xxxVar(&变量, 参数名, 默认值, 帮助信息)
   flag.StringVar(&name, "name", "caixukun.666", "姓名")
   flag.IntVar(&studentId, "id", 128, "学号")
   flag.BoolVar(&isMale, "male", false, "是男性")

   // 注意一定要有解析 否则变量都是默认值
   flag.Parse()

   // 查看解析结果
   fmt.Printf("Name=%s, StudentId=%d, IsMale=%t\n", name, studentId, isMale)
}

2. 有子命令的情况

类似于docker container -ls 中container 就是一个子命令

1. 这种情况下需要首先解析一次。否则flag.Args是无效的。

2. 使用flag.Args()[0] 来判断使用的是哪个子命令

3. 然后重新创建一个命名的flagSet 进一步解析 flag.Args[1:] 部分的命令行参数作为子命令的命令行参数

package main

import (
   "flag"
   "fmt"
)

// 适用于有子命令的情况

// 不带有等号的格式
// eg:  student子命令: go run main.go student -name ikun -id 29238 -male
// eg:  student子命令: go run main.go teacher -name mayun -salary 20000

// 带有等号的格式
// eg:  student子命令: go run main.go student -name=ikun -id=29238 -male
// eg:  student子命令: go run main.go teacher -name=mayun -salary=20000
func main() {
   //首先要用全局默认FlagSet解析一遍 否则flag.Args是无效的。
   flag.Parse()
   flagArgs := flag.Args()
   switch flagArgs[0] {
   case "student":// student子命令解析
      var name string
      var studentId int
      var isMale bool
      stuendtFlags := flag.NewFlagSet("student", flag.ExitOnError)
      stuendtFlags.StringVar(&name, "name", "caixukun.666", "姓名")
      stuendtFlags.IntVar(&studentId, "id", 128, "学号")
      stuendtFlags.BoolVar(&isMale, "male", false, "是否男性")

      // 索引从1开始 索引0是子命令 "student" 字符串
      err := stuendtFlags.Parse(flagArgs[1:])
      if err != nil {
         fmt.Printf("Student Invalid cmd option\n")
         return
      }
      fmt.Printf("Student: Name=%s, StudentId=%d, IsMale=%t\n", name, studentId, isMale)
   case "teacher":
      var name string
      var salary int64
      teacherFlags := flag.NewFlagSet("teacher", flag.ExitOnError)
      teacherFlags.StringVar(&name, "name", "caixukun.666", "姓名")
      teacherFlags.Int64Var(&salary, "salary", 128, "薪资")
      err := teacherFlags.Parse(flagArgs[1:])
      if err != nil {
         fmt.Printf("Teacher Invalid cmd option\n")
         return
      }
      fmt.Printf("Teacher: Name=%s, Salary=%d\n", name, salary)
   default:
      fmt.Printf("Invalid cmd option\n")
   }
}

三、mow.cli

地址:https://github.com/jawher/mow.cli

著名的基于Go语言的爬虫框架colly就是基于此命令行框架。

简单举例,更复杂的见官网:

package main

import (
	"fmt"
	"os"

	"github.com/jawher/mow.cli"
)

func main() {
	// create an app
	app := cli.App("cp", "Copy files around")

	// Here's what differentiates mow.cli from other CLI libraries:
	// This line is not just for help message generation.
	// It also validates the call to reject calls with less than 2 arguments
	// and split the arguments between SRC or DST
	app.Spec = "[-r] SRC... DST"

	var (
		// declare the -r flag as a boolean flag
		recursive = app.BoolOpt("r recursive", false, "Copy files recursively")
		// declare the SRC argument as a multi-string argument
		src = app.StringsArg("SRC", nil, "Source files to copy")
		// declare the DST argument as a single string (string slice) arguments
		dst = app.StringArg("DST", "", "Destination where to copy files to")
	)

	// Specify the action to execute when the app is invoked correctly
	app.Action = func() {
		fmt.Printf("Copying %v to %s [recursively: %v]\n", *src, *dst, *recursive)
	}

	// Invoke the app passing in os.Args
	app.Run(os.Args)
}


参考

  • https://zhuanlan.zhihu.com/p/597566246
  • https://blog.csdn.net/qq_30614345/article/details/130977888
  • https://github.com/jawher/mow.cli




举报

相关推荐

0 条评论