Golang的一个CLI框架
因为机缘巧合,因为希望能在VPS中使用百度网盘,了解到了一个开源的项目BaiduPCS-Go,可以用来直接存取访问百度网盘,做的相当不错
而且看ISSUES,作者可能还是个学生,很强的样子。稍微看了下代码,发现了一个很不错的用来写命令行程序CLI的框架,也是在Github上开源的,因为Golang主要是用来写这个的,所以感觉比较有用的样子,学习一下,并且稍微做了个笔记。
这个框架就是
github.com/urfave/cli
稍微整理了下具体使用的方式
1,最初的版本,如何引入等等
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli"
) func main() {
app := cli.NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Action = func(c *cli.Context) error {
fmt.Println("boom! I say!")
return nil
} err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
这里的 app.Action 中间的,就是CLI执行(回车)后的操作。乍看没啥东西,其实这个时候已经封装了 -help -version等等的方法了
执行这个GO程序,控制台输出 boom! I say! 如果执行 main -help 则输出命令行的帮助,类似下面的样子
NAME:
boom - make an explosive entrance USAGE:
002 [global options] command [command options] [arguments...] VERSION:
0.0.0 COMMANDS:
help, h Shows a list of commands or help for one command GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
2,慢慢深入,接下来有参数,也就是执行的时候 XXX.EXE Arg这个Arg部分如何处理
package main import (
"fmt"
"log"
"os" "github.com/urfave/cli"
) func main() {
app := cli.NewApp() app.Action = func(c *cli.Context) error {
//获取第一个参数
fmt.Printf("Hello %q", c.Args().Get(0))
return nil
} err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
这时候输入 参数1 ,则控制台返回 hello “1”;
3,关于FLAG
有很多命令行程序有flag 比如linux下的常用的 netstat -lnp 等等
package main import (
"fmt"
"log"
"os" "github.com/urfave/cli"
) func main() {
app := cli.NewApp() app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
} app.Action = func(c *cli.Context) error {
name := "Nefertiti"
if c.NArg() > 0 {
name = c.Args().Get(0)
}
if c.String("lang") == "spanish" {
fmt.Println("Hola", name)
} else {
fmt.Println("Hello", name)
}
return nil
} err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
这个时候我们执行 002.go –lang english 控制台会输出 Hello Nefertiti;执行002.go –lang spanish,则会输出 Hola Nefertiti。
在程序里,通过 判断 c.String(“lang”) 来决定程序分叉
当然程序稍微修改一下,通过一个属性也能对参数赋值
app.Flags = []cli.Flag {
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
Destination: &language, //取到的FLAG值,赋值到这个变量
},
}
使用的时候只要用 language 来判断就行了
4.关于commond和subcommand
package main import (
"fmt"
"log"
"os" "github.com/urfave/cli"
) func main() {
app := cli.NewApp() app.Commands = []cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) error {
fmt.Println("added task: ", c.Args().First())
return nil
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) error {
fmt.Println("completed task: ", c.Args().First())
return nil
},
},
{
Name: "template",
Aliases: []string{"t"},
Usage: "options for task templates",
Subcommands: []cli.Command{
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) error {
fmt.Println("new task template: ", c.Args().First())
return nil
},
},
{
Name: "remove",
Usage: "remove an existing template",
Action: func(c *cli.Context) error {
fmt.Println("removed task template: ", c.Args().First())
return nil
},
},
},
},
} err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
上面的例子里面,罗列了好多个commond以及subcommand,通过定义这些,我们能实现 类似
可执行程序 命令 子命令的操作,比如 App.go add 123 控制台输出 added task: 123
只要遵循框架,这个时候这些命令(Command)以及FLAG的帮助说明都是自动生成的。比如上面这个程序的help,控制台会输出所有使用方式
类似
NAME:
002 - A new cli application USAGE:
002 [global options] command [command options] [arguments...] VERSION:
0.0.0 COMMANDS:
add, a add a task to the list
complete, c complete a task on the list
template, t options for task templates
help, h Shows a list of commands or help for one command GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
最后,稍微扩张一下,类似MYSQL,FTP,TELNET等工具,很多控制台程序,都是进入类似一个自己的运行界面,这样其实CLI本身因为并没有中断,可以保存先前操作的信息。
所以比如FTP,TELNET,Mysql这种需要权限的工具,广泛使用。这时,我们往往只需要用户登陆一次,就可以继续执行上传下载查询通讯等等的后续操作。
废话不多说,直接上例子
package main import (
"fmt"
"log"
"os"
"strings"
"bufio"
"github.com/urfave/cli"
) func main() {
app := cli.NewApp() app.Action = func(c *cli.Context) {
if c.NArg() != 0 {
fmt.Printf("未找到命令: %s\n运行命令 %s help 获取帮助\n", c.Args().Get(0), app.Name)
return
} var prompt string prompt = app.Name + " > "
L:
for {
var input string
fmt.Print(prompt)
// fmt.Scanln(&input) scanner := bufio.NewScanner(os.Stdin)
scanner.Scan() // use `for scanner.Scan()` to keep reading
input = scanner.Text()
//fmt.Println("captured:",input)
switch input {
case "close":
fmt.Println("close.")
break L
default:
}
//fmt.Print(input)
cmdArgs := strings.Split(input, " ")
//fmt.Print(len(cmdArgs))
if len(cmdArgs) == 0 {
continue
} s := []string{app.Name}
s = append(s,cmdArgs...) c.App.Run(s) } return
} app.Commands = []cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) error {
fmt.Println("added task: ", c.Args().First())
return nil
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) error {
fmt.Println("completed task: ", c.Args().First())
return nil
},
},
{
Name: "template",
Aliases: []string{"t"},
Usage: "options for task templates",
Subcommands: []cli.Command{
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) error {
fmt.Println("new task template: ", c.Args().First())
return nil
},
},
{
Name: "remove",
Usage: "remove an existing template",
Action: func(c *cli.Context) error {
fmt.Println("removed task template: ", c.Args().First())
return nil
},
},
},
},
} err := app.Run(os.Args) if err != nil {
log.Fatal(err)
}
}
这里在Action里面,其实加入了一个死循环,一直在听取程序的输入,直接执行(回车)的话,其实进入一个类似MySQL或者FTP类似的命令行界面。等待用户的进一步输入。
然后读取这个输入,通过调用原来的框架的app.Run(os.Args)来处理需求逻辑。
上述所有基本涵盖了命令行的所有可能的形式,以后就可以按照这个框架写出起码帮助感觉很正式的程序了。
Golang的一个CLI框架的更多相关文章
- 使用golang写一个redis-cli
使用golang写一个redis-cli 0. redis通信协议 redis的客户端(redis-cli)和服务端(redis-server)的通信是建立在tcp连接之上, 两者之间数据传输的编码解 ...
- Golang最强大的访问控制框架casbin全解析
Golang最强大的访问控制框架casbin全解析 Casbin是一个强大的.高效的开源访问控制框架,其权限管理机制支持多种访问控制模型.目前这个框架的生态已经发展的越来越好了.提供了各种语言的类库, ...
- 如何使用Golang实现一个API网关
你是否也存在过这样的需求,想要公开一个接口到网络上.但是还得加点权限,否则被人乱调用就不好了.这个权限验证的过程,最好越简单越好,可能只是对比两个字符串相等就够了.一般情况下我们遇到这种需要,就是在函 ...
- 使用Prometheus监控Golang服务-基于YoyoGo框架
Prometheus Prometheus是一个非常棒的工具,结合grafana能够让我在不写代码,或者少写代码的情况下搭建一套有效的监控体系.这里介绍一下Prometheus监控golang程序的方 ...
- Go语言笔记[实现一个Web框架实战]——EzWeb框架(一)
Go语言笔记[实现一个Web框架实战]--EzWeb框架(一) 一.Golang中的net/http标准库如何处理一个请求 func main() { http.HandleFunc("/& ...
- Golang语言系列-17-Gin框架
Gin框架 Gin框架简介 package main import ( "github.com/gin-gonic/gin" "io" "net/ht ...
- Fastflow——基于golang的轻量级工作流框架
Fastflow 是什么?用一句话来定义它:一个 基于golang协程.支持水平扩容的分布式高性能工作流框架. 它具有以下特点: 易用性:工作流模型基于 DAG 来定义,同时还提供开箱即用的 API, ...
- 如何实现一个php框架系列文章【开篇】
1.本系列文章的目的 实现一个小而美的产品级别php框架 自己动手实现一个新框架仅用于学习交流,不打算替代市面上现有的其他主流框架. 2. 我要一个怎样的PHP框架 简单实用,安全优雅,博采众长 安装 ...
- 第一个web框架tornado
简介 tornado,是我学到的第一个web框架是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本.这个 Web 框架看起来有些像web.py 或者 Google ...
随机推荐
- Poi导出Excle
场景 准备金系统需要从数据库读取大量数据存放到List集合中(可能还会做逻辑上的处理),并生成一个Excle文件,下载到客户本地. 问题一:客户体验 如果导出的文件比较大,比如几十万条数据,同步导出页 ...
- 数据管理必看!Kendo UI for jQuery过滤器的全球化
Kendo UI for jQuery最新试用版下载 Kendo UI目前最新提供Kendo UI for jQuery.Kendo UI for Angular.Kendo UI Support f ...
- JS 实现复制一个或多个内容到剪贴板
需要实现的功能:点击button,复制如下值到剪贴板, 链接:http://192.168.0.203:7083/share/nRrDLqBBJFjXQ5lk9Nv60GV6 提取码: 3NmH 常用 ...
- Acwing-204-表达整数的奇怪方式(扩展中国剩余定理)
链接: https://www.acwing.com/problem/content/206/ 题意: 给定2n个整数a1,a2,-,an和m1,m2,-,mn,求一个最小的非负整数x,满足∀i∈[1 ...
- SQL进程死锁排查
--进程执行状态 SELECT der.[session_id],der.[blocking_session_id], sp.lastwaittype,sp.hostname,sp.program_n ...
- 配置并访问NFS共享
NFS服务器 192.168.2.5 NFS客户机 192.168.2.100 软件包nfs-utils用来提供NFS共享服务及相关工具,而软件包rpcbind用来提供RPC协议的支持 服务器 修改/ ...
- query mousedown()方法 语法
query mousedown()方法 语法 作用:当鼠标指针移动到元素上方,并按下鼠标按键时,会发生 mousedown 事件.与 click 事件不同,mousedown 事件仅需要按键被按下,而 ...
- React Native 项目常用第三方组件汇总
React Native 项目常用第三方组件汇总 https://www.jianshu.com/p/d9cd9a868764?utm_campaign=maleskine&utm_conte ...
- codevs 1013 求先序排列 2001年NOIP全国联赛普及组 x
题目描述 Description 给出一棵二叉树的中序与后序排列.求出它的先序排列.(约定树结点用不同的大写字母表示,长度<=8). 输入描述 Inpu ...
- AtCoder AGC031D A Sequence of Permutations (群论、置换快速幂)
题目链接 https://atcoder.jp/contests/agc031/tasks/agc031_d 题解 这居然真的是个找规律神题... 首先要明白置换的一些基本定义,置换\(p\)和\(q ...