拥抱结构体的命令行解析器, clop v0.0.2+v0.0.3 版本发布! - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
guonaihong
V2EX    Go 编程语言

拥抱结构体的命令行解析器, clop v0.0.2+v0.0.3 版发布!

  •  
  •   guonaihong
    guonaihong 2020-04-01 09:41:21 +08:00 1968 次点击
    这是一个创建于 2110 天前的主题,其中的信息可能已经有所发展或是发生改变。

    clop

    Go codecov Go Report Card

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

    项目地址

    https://github.com/guonaihong/clop

    changlog

    • bugfix
    • 可以获取命令行优先级别,主要在 shell 里面设置 alias 会用到

    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) 

    Get command priority

    package main import ( "fmt" "github.com/guonaihong/clop" ) type cat struct { NumberNonblank bool `clop:"-b;--number-nonblank" usage:"number nonempty output lines, overrides"` ShowEnds bool `clop:"-E;--show-ends" usage:"display $ at end of each line"` } func main() { c := cat{} clop.Bind(&c) if clop.GetIndex("number-nonblank") < clop.GetIndex("show-ends") { fmt.Printf("cat -b -E\n") } else { fmt.Printf("cat -E -b \n") } } // cat -be // 输出 cat -b -E // cat -Eb // 输出 cat -E -b 

    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> */ 
    6 条回复    2020-04-01 13:08:42 +08:00
    LoNeFong
        1
    LoNeFong  
       2020-04-01 10:04:30 +08:00
    支持
    guonaihong
        2
    guonaihong  
    OP
       2020-04-01 11:34:46 +08:00
    @LoNeFong 感谢。。。
    ulala
        3
    ulala  
       2020-04-01 12:38:32 +08:00 via iPhone
    和标准库的 flag 相比,有什么优势呢
    koalr
        4
    koalr  
       2020-04-01 12:43:52 +08:00 via Android
    感觉还不如写代码直观
    guonaihong
        5
    guonaihong  
    OP
       2020-04-01 13:05:57 +08:00
    @ulala 可以开发 gnu 风格命令行。flag 库不行。
    guonaihong
        6
    guonaihong  
    OP
       2020-04-01 13:08:42 +08:00
    @koalr 我一开始的观点和你一样。后面写了几十,几百个命令,最后得出这种方式比较爽。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2656 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 02:04 PVG 10:04 LAX 18:04 JFK 21:04
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86