前言
在golang中有很多方法来处理命令行参数,简单情况下可以不使用任何库,直接使用os.Args;
但是golang标准库提供了flag包来专门处理命令行参数
;
当然还有第三方提供的处理命令行参数的库cobra、cli可以参考。
flag包绑定解析参数的三种定义方式
(1) flag.Xxx() 例如:flag.Int, flag.String, 返回解析变量类型的指针
package main
import (
"flag"
"fmt"
)
var (
host *string
port *int
)
func init() {
host = flag.String("host", "127.0.0.1", "请输入host地址")
port = flag.Int("port", 3306, "请输入端口号")
}
func main() {
flag.Parse() // 解析参数
fmt.Printf("%s:%d\n", *host, *port)
}
执行:go run main.go
输出:127.0.0.1:3306
执行: go run main.go -host=192.168.0.1 -port=8080
输出:192.168.0.1:8080
执行:go run main.go -host 192.168.0.1
输出:192.168.0.1:3306
执行:go run main.go -host=192.168.0.1 -port
输出:invalid value "" for flag -port: parse error
Usage of xxxxx/exe/main:
-host string
请输入host地址 (default "127.0.0.1")
-port int
请输入端口号 (default 3306)
exit status 2
执行:go run main.go -h
输出:Usage of xxxxx/exe/main:
-host string
请输入host地址 (default "127.0.0.1")
-port int
请输入端口号 (default 3306)
(2) flag.XxxVar() 例如:flag.IntVar, flag.StringVar 获取解析变量类型的值
package main
import (
"flag"
"fmt"
)
var (
host string
port int
)
func init() {
flag.StringVar(&host, "host", "127.0.0.1", "请输入host地址")
flag.IntVar(&port, "port", 3306, "请输入端口号")
}
func main() {
flag.Parse() // 解析参数
fmt.Printf("%s:%d\n", host, port)
}
执行效果同上
(3)自定义参数解析flag.Var()
我们可以看下flag.go源码:
func Var(value Value, name string, usage string) {
CommandLine.Var(value, name, usage)
}
type Value interface {
String() string
Set(string) error
}
使用flag.Var函数第一个参数我们需要传入一个Value类型的值,Value是一个接口类型,定义了两个方法。
接下来我们去实现这两个方法:
package main
import (
"flag"
"fmt"
"strings"
)
// 自定义类型
type HandsomeBoys []string
// 实现String()方法
func (h *HandsomeBoys) String() string {
return fmt.Sprintf("%v", *h)
}
// 实现Set方法,Set接口决定了如何解析flag的值
func (h *HandsomeBoys) Set(s string) error {
for _, v := range strings.Split(s, ",") {
*h = append(*h, v)
}
return nil
}
// 定义一个HandsomeBoys类型的变量
var boys HandsomeBoys
func init() {
// 绑定变量boys
flag.Var(&boys, "boys", "请输入一组帅气的男孩名称:-boys=彭于晏,吴彦祖")
}
func main() {
flag.Parse()
fmt.Println(boys)
}
输入:go run var/main.go
输出:[]
输入:go run var/main.go -boys=吴彦波,胡歌
输出:[吴彦波 胡歌]
拓展
1、go的os模块
使用 os.Args
也能获取命令行参数,但是这个功能有点欠缺。
例如不能接收像-u root -p 3306这样指定key的值,只能接收像root 3306这样的方式。
示例:
package main
import (
"fmt"
"os"
)
var cmdArgs []string
func init() {
cmdArgs = os.Args
}
func main() {
for index, value := range cmdArgs {
fmt.Printf("索引:%v,value值:%v\n", index, value)
}
}
输入:go build -o main.exe main.go
./main.exe root 3306
输出:索引:0,value值:./main.exe
索引:1,value值:root
索引:2,value值:3306
注:返回的cmdArgs是一个切片,第一个值是自己的文件名。
如果不想要自己第一个值,直接 cmdArgs = os.Args[1:]
即可。
2、viper + flag
有意思的是,可以将viper同flag结合使用。
示例:
package main
import (
"flag"
"fmt"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func main() {
// using standard library "flag" package
flag.String("flagname", "root", "help message for flagname")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
myFlagname := viper.GetString("flagname") // retrieve value from viper
fmt.Println("myFlagname:", myFlagname)
}
输入:go run flagUtil.go -h
输出:Usage of xxxxx/exe/flagUtil:
--flagname string help message for flagname (default "root")
pflag: help requested
输入:go run flagUtil.go
输出:myFlagname: 1234
输入:go run flagUtil.go --flagname 吴彦波
输出:myFlagname: 吴彦波