Golang Go语言中 超级简单 只要会写结构体 就能解析命令行 clop 发布啦

发布于 1周前 作者 nodeper 来自 Go语言

Golang Go语言中 超级简单 只要会写结构体 就能解析命令行 clop 发布啦

clop

clop 是一款基于 struct 的命令行解析器,麻雀虽小,五脏俱全。

项目地址

https://github.com/guonaihong/clop

clop

Go codecov Go Report Card

feature

  • 支持环境变量绑定 env DEBUG=xx ./proc
  • 支持参数搜集 cat a.txt b.txt,可以把a.txt, b.txt散装成员归归类,收集到你指定的结构体成员里
  • 支持短选项proc -d 或者长选项proc --debug不在话下
  • posix 风格命令行支持,支持命令组合ls -ltrls -l -t -r简写形式,方便实现普通 posix 标准命令
  • 子命令支持,方便实现 git 风格子命令git add,简洁的子命令注册方式,只要会写结构提就行,3,4,5 到无穷尽子命令也支持,只要你喜欢,用上 clop 就可以实现
  • 默认值支持default:"1",支持多种数据类型,让你省去类型转换的烦恼
  • 贴心的重复命令报错
  • 严格的短选项,长选项报错。避免二义性选项诞生
  • 效验模式支持,不需要写一堆的if x!= "" or if y!=0浪费青春的代码

内容

Installation

go get github.com/guonaihong/clop

Quick start

package main

import ( “fmt” “github.com/guonaihong/clop” )

type Hello struct { File string clop:"-f; --file" usage:"file" }

func main() {

h := Hello{}
clop.Bind(&h)
fmt.Printf("%#v\n", h)

} // ./one -f test // main.Hello{File:“test”} // ./one --file test // main.Hello{File:“test”}

example

required flag

 package main

import ( “fmt” “github.com/guonaihong/clop” )

type curl struct { Url string clop:"-u; --url" usage:"url" valid:"required" }

func main() {

c := curl{}
clop.Bind(&c)

}

set default value

可以使用 default tag 设置默认值,普通类型直接写,复合类型用 json 表示

package main

import ( “fmt” “github.com/guonaihong/clop” )

type defaultExample struct { Int int default:"1" Float64 float64 default:"3.64" Float32 float32 default:"3.32" SliceString []string default:"[\"one\", \"two\"]" SliceInt []int default:"[1,2,3,4,5]" SliceFloat64 []float64 default:"[1.1,2.2,3.3,4.4,5.5]" }

func main() { de := defaultExample{} clop.Bind(&de) fmt.Printf("%v\n", de) } // run // ./use_def // output: // {1 3.64 3.32 [one two] [1 2 3 4 5] [1.1 2.2 3.3 4.4 5.5]}

Support environment variables

// file name use_env.go
package main

import ( “fmt” “github.com/guonaihong/clop” )

type env struct { OmpNumThread string clop:"env=omp_num_thread" usage:"omp num thread" Path string clop:"env=XPATH" usage:"xpath" Max int clop:"env=MAX" usage:"max thread" }

func main() { e := env{} clop.Bind(&e) fmt.Printf("%#v\n", e) } // run // env XPATH=pwd omp_num_thread=3 MAX=4 ./use_env // output // main.env{OmpNumThread:“3”, Path:"/home/guo", Max:4}

subcommand

package main

import ( “fmt” “github.com/guonaihong/clop” )

type add struct { All bool clop:"-A; --all" usage:"add changes from all tracked and untracked files" Force bool clop:"-f; --force" usage:"allow adding otherwise ignored files" Pathspec []string clop:"args=pathspec" }

type mv struct { Force bool clop:"-f; --force" usage:"allow adding otherwise ignored files" }

type git struct { Add add clop:"subcommand=add" usage:"Add file contents to the index" Mv mv clop:"subcommand=mv" usage:"Move or rename a file, a directory, or a symlink" }

func main() { g := git{} clop.Bind(&g) fmt.Printf(“git:%#v\n”, g) fmt.Printf(“git:set mv(%t) or set add(%t)\n”, clop.IsSetSubcommand(“mv”), clop.IsSetSubcommand(“add”)) } // run: // ./git add -f

// output: // git:main.git{Add:main.add{All:false, Force:true, Pathspec:[]string(nil)}, Mv:main.mv{Force:false}} // git:set mv(false) or set add(true)

Implementing linux command options

cat

package main

import ( “fmt” “github.com/guonaihong/clop” )

type cat struct { NumberNonblank bool clop:"-c;--number-nonblank" usage:"number nonempty output lines, overrides"

ShowEnds bool `clop:"-E;--show-ends" 
               usage:"display $ at end of each line"`

Number bool `clop:"-n;--number" 
             usage:"number all output lines"`

SqueezeBlank bool `clop:"-s;--squeeze-blank" 
                   usage:"suppress repeated empty output lines"`

ShowTab bool `clop:"-T;--show-tabs" 
              usage:"display TAB characters as ^I"`

ShowNonprinting bool `clop:"-v;--show-nonprinting" 
                      usage:"use ^ and M- notation, except for LFD and TAB" `

Files []string `clop:"args=files"`

}

func main() {

c := cat{}
err := clop.Bind(&c)

fmt.Printf("%#v, %s\n", c, err)

}

/* Usage: ./cat [Flags] <files>

Flags: -E,–show-ends display $ at end of each line -T,–show-tabs display TAB characters as ^I -c,–number-nonblank number nonempty output lines, overrides -n,–number number all output lines -s,–squeeze-blank suppress repeated empty output lines -v,–show-nonprinting use ^ and M- notation, except for LFD and TAB

Args: <files> */

题外话

掐指一算,等会儿会有 viper 的粉丝出现。这里提前预判。为啥要出这个库,大约是 19 年的时候 挑战过 gnu 123 个命令,最后完成了 30-40 的样子。一开始使用函数形式的解析库,过程是这样的
1.定义结构体
2.复制命令行选项,复制 usage 信息
3.把刚刚复制的信息分解到定义解析函数,再配置一堆项
4.解析
事是很简单,但是一个命令选项如果不少,定完数据结构,配置好 usage,跑完测试估计 30 分钟时间就没了。这里面发掘了慢的原因--数据离绑定的地方太远,修改返工花时间。 针对上面的问题,一直在思考如何让这个简单的事情变得更快呢?最近选择了 struct 的形式,当然也考虑过 ast,最后排除了。选择 struct 这种形式是经过实战考验的。


更多关于Golang Go语言中 超级简单 只要会写结构体 就能解析命令行 clop 发布啦的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

zici

更多关于Golang Go语言中 超级简单 只要会写结构体 就能解析命令行 clop 发布啦的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


先星星再研究

非常喜欢这个方式,感觉命令行这样简单了许多,比起来 flag 包和 cobra 简单多了。

另外问下 validator 可以使用 validator.v8 之类的吗?

看了下 validator,本身就是用的 validator.v10 ,非常好

感谢支持。。。

你好!很高兴看到你对Golang中的命令行解析工具clop感兴趣。确实,Golang以其简洁而强大的特性,使得开发高效、易维护的命令行工具成为可能。clop作为一个基于结构体的命令行解析库,进一步简化了这一过程。

在Go语言中,结构体(struct)是一种复合数据类型,它允许你将数据(零个或多个,任意类型)组合成一个单一的类型。clop正是利用了结构体的这一特性,通过定义结构体字段和相应的标签(tag),来自动解析命令行参数。

使用clop,你只需定义一个结构体,其字段对应你想要从命令行接收的参数,然后使用clop提供的函数进行解析。clop会自动处理参数的匹配、类型转换和错误处理,从而大大减少了手动编写解析代码的工作量。

此外,clop还支持自动生成帮助信息和用法说明,使得你的命令行工具更加友好和易用。用户只需通过简单的命令行选项,即可了解如何正确使用你的工具。

总的来说,clop是一个强大且易用的命令行解析库,它充分利用了Go语言的结构体特性,使得命令行工具的开发变得更加简单和高效。如果你对命令行解析有需求,不妨尝试一下clop,相信它会给你带来不一样的开发体验。

回到顶部