Go GetoptGo 解析命令行參數(shù)工具
Go GetOpt,讓你在 go 里解析命令行參數(shù)無聊地跟寫 shell 腳本一樣。
為了不引起混淆,以下說明將使用
go getopt 表示本代碼倉庫
shell getopt、getopt 命令 表示 util-linux 中的 getopt 二進制程序
getopt(或 C getopt)表示 libc 中的 getopt 方法
但在某個上下文(如標題說明了該段是 shell getopt)中可能有時會直接使用 getopt 指代。請各位注意區(qū)分。
怎么用
go get gitee.com/go-getopt/go-getopt
package main
import (
"fmt"
"os"
// 這里為了方便,直接使用 . 進行 import。
// 這樣可以直接調(diào)用 GetOpt、Get 和 Shift 方法。
. "gitee.com/go-getopt/go-getopt"
)
func main() {
// 傳入 os.Args、options 和 longOptions 字符串參數(shù)即可
err := GetOpt(os.Args, "ab:c::", "a-long,b-long:,c-long::")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// 解析后的參數(shù)列表存儲在全局變量 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
# 設(shè)定 options 和 longOptions,調(diào)用 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"
# 循環(huán)判斷是哪個 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 程序解析命令行參數(shù)方便一點。
- 只想解析出字符串形式參數(shù),然后自己做處理或轉(zhuǎn)換。
- 不想讓類型斷言、類型轉(zhuǎn)換代碼到處亂飛,也不需要調(diào)用的庫提供
GetInt、MustGetInt之類的方法。 -
忘不了前任習慣了寫 shell,想找個差不多的庫接盤。 - 不喜歡
flag、pflag這種類型的解析方式(pflag也很久沒維護了)。 - 不想用
cobra這種很繁瑣的庫。
其他問題
并發(fā)(協(xié)程)安全嗎?
沒辦法做到,也沒必要。C 的 getopt 和 getopt_long 方法本身就不是并發(fā)安全的(用了全局變量 optind、optarg 來存儲中間狀態(tài))。
而且,命令行應(yīng)該只需要解析一次就可以了吧。有必要多次解析嗎???
支持哪些平臺?
這個庫是用 cgo 包裝 libc 中的 getopt_long 方法實現(xiàn)的。原理和 shell getopt 命令行程序差不多。目前主流的 libc 都是支持的:
-
mingw/msvcWindows 系 -
glibcDebian 系、CentOS 系 -
muslAlpine -
uclibc-ngBusyBox
附:各 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
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
