您现在的位置是:首页 > 文章详情

Go Getopt —— Go 解析命令行参数工具

日期:2022-02-28点击:568

Go GetOpt,让你在 go 里解析命令行参数无聊地跟写 shell 脚本一样。


为了不引起混淆,以下说明将使用

go getopt 表示本代码仓库

shell getoptgetopt 命令 表示 util-linux 中的 getopt 二进制程序

getopt(或 C getopt)表示 libc 中的 getopt 方法

但在某个上下文(如标题说明了该段是 shell getopt)中可能有时会直接使用 getopt 指代。请各位注意区分。


怎么用

 go get gitee.com/go-getopt/go-getopt 
 package main import ( "fmt" "os" // 这里为了方便,直接使用 . 进行 import。 // 这样可以直接调用 GetOpt、Get 和 Shift 方法。 . "gitee.com/go-getopt/go-getopt" ) func main() { // 传入 os.Args、options 和 longOptions 字符串参数即可 err := GetOpt(os.Args, "ab:c::", "a-long,b-long:,c-long::") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } // 解析后的参数列表存储在全局变量 Args 中 fmt.Println("Arguments:", Args) fmt.Println("Program name:", Args[0]) // 接下来的步骤就和 shell 差不多了 for loop := true; loop; { switch Get(1) { case "-a", "--a-long": fmt.Println("Option a") Shift(1) case "-b", "--b-long": fmt.Println("Option b, argument '" + Get(2) + "'") Shift(2) case "-c", "--c-long": if Get(2) == "" { fmt.Println("Option c, no argument") } else { fmt.Println("Option c with arg '" + Get(2) + "'") } Shift(2) case "--": Shift(1) loop = false default: fmt.Fprintln(os.Stderr, "Error: wrong argument '"+arg1+"'") os.Exit(1) } } fmt.Println("Remains:", Args[1:]) } 

对比一下 shell getopt 解析命令行的脚本:

 # 检查 getopt 命令是否正常运行 getopt --test > /dev/null [ $? -ne 4 ] && echo "Error: command 'getopt --test' failed in this environment." && exit 1 # 设定 options 和 longOptions,调用 getopt 命令 options=ab:c:: longOptions=a-long,b-long:,c-long:: parsed=$(getopt --options=$options --longoptions=$longOptions --name "$0" -- "$@") [ $? -ne 0 ] && echo "Error: failed to parse cmd arguments" && exit 1 eval "set -- $parsed" # 循环判断是哪个 flag,处理完后 shift 掉 while true; do case "$1" in -a|--a-long) echo 'Option a' shift ;; -b|--b-long) echo "Option b, argument '$2'" shift 2 ;; -c|--c-long) [ -n "$2" ] && \\ echo "Option c, argument '$2'" || \\ echo 'Option c, no argument' shift 2 --) shift break *) echo "Error: wrong argument '$1'" exit 1 ;; esac done echo "Remains: $@" 

Go GetOpt 适合哪些人用

如果你符合以下的一条或多条,可能这个库会适合你:

  • 想用一个库让 go 程序解析命令行参数方便一点。
  • 只想解析出字符串形式参数,然后自己做处理或转换。
  • 不想让类型断言、类型转换代码到处乱飞,也不需要调用的库提供 GetIntMustGetInt 之类的方法。
  • 忘不了前任 习惯了写 shell,想找个差不多的库接盘
  • 不喜欢 flagpflag 这种类型的解析方式(pflag 也很久没维护了)。
  • 不想用 cobra 这种很繁琐的库。

其他问题

并发(协程)安全吗?

没办法做到,也没必要。C 的 getoptgetopt_long 方法本身就不是并发安全的(用了全局变量 optindoptarg 来存储中间状态)。

而且,命令行应该只需要解析一次就可以了吧。有必要多次解析吗🤔?

支持哪些平台?

这个库是用 cgo 包装 libc 中的 getopt_long 方法实现的。原理和 shell getopt 命令行程序差不多。目前主流的 libc 都是支持的:

  • mingw / msvc Windows 系
  • glibc Debian 系、CentOS 系
  • musl Alpine
  • uclibc-ng BusyBox

附:各 libc getopt 和 getopt_long 源码地址

musl

https://git.musl-libc.org/cgit/musl/tree/src/misc/getopt.c

https://git.musl-libc.org/cgit/musl/tree/src/misc/getopt_long.c

glibc

https://sourceware.org/git/?p=glibc.git;a=blob;f=posix/getopt.c;h=e9661c79faa8920253bc37747b193d1bdcb288ef;hb=HEAD

https://sourceware.org/git/?p=glibc.git;a=blob;f=posix/getopt1.c;h=990eee1b64fe1ee03e8b22771d2e88d5bba3ac68;hb=HEAD

uclibc-ng

https://gogs.waldemar-brodkorb.de/oss/uclibc-ng/src/master/libc/unistd/getopt.c

https://gogs.waldemar-brodkorb.de/oss/uclibc-ng/src/master/libc/unistd/getopt_long-simple.c

原文链接:https://www.oschina.net/p/go-getopt
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章