大部分Go程序是没有UI的,运行在纯命令行的模式下,该干什么全靠运行时参数。这里详解一下Go语言的命令行程序和参数。
1.os.Args
程序可以通过os包来获取运行时的参数,示例如下:
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
for idx, args := range os.Args {
fmt.Println("参数" + strconv.Iota(idx) + ":" args)
}
}
运行得到如下结果:
$ go run os_flat.go 1 false —a ? -
参数0:/var/folders/jd/_nrr3p2x5pncw4y0trf_0bq40000gn/T/go-build1510265706/b001/exe/os_flat
参数1:1
参数2:false
参数3:—a
参数4:?
参数5:-
可以看到,命令行参数包括了程序路径本身,以及通常意义上的参数。
程序中,os.Args类型是[]string, 即字符串切片。所以可以使用for range循环遍历,还可以使用len(os.Args)来获取全部参数数量。
如果不想输出可执行文件本身的信息,可以切片。
for idx, args := range os.Args[1:] {
}
输出切片的所有元素,有更简洁的方式:
fmt.Println(strings.Join(os.Args[1:0]), "\n")
fmt.Println(os.Args[1:]) // [1 false —a ? -] 这是fmt.Println输出切片的格式
2.flag包
flag包相比单纯地通过os.Args
切片分析命令行参数,提供更强的能力。
在写命令行程序时,对命令行参数进行解析是常见的需求。各种语言一般都会提供解析命令行参数的方法或库,以方便程序员使用。在go标准库中提供了一个包:flag,方便进行命令行解析。flag包中类似 String()
或者 StringVar()
这样的方法仅仅是把参数名以及接收值的内存地址还有默认值等参数关联起来,并没有真正将arguments 解析注册到flag。因此必须要在定义接收好flag参数之后并且在访问这些参数前调用 flag.Parse()
。
package main
import (
"fmt"
"flag"
)
func main() {
// 定义几个变量,用于接收命令行参数值
var user string
var pwd string
var host string
var port int
// &user 用来接收命令行中输入的 -u 后面的参数值
// "u" 就是 -u 指定的参数
// "" 默认值
// “用户名,默认为空” 说明
flag.StringVar(&user, "u", "", "用户名,默认为空")
flag.StringVar(&pwd, "pwd", "", "密码,默认为空")
flag.StringVar(&host, "h", "localhost", "主机名,默认为localhost")
flag.IntVar(&port, "port", 3306, "端口号,默认3306")
// 【必须调用】 从arguments 中解析注册到flag
flag.Parse()
// 输出结果
fmt.Printf("\n user = %v \n pwd=%v \n host=%v \n port=%v \n", user, pwd, host, port)
}
两种运行方式都可以:
$ go run go_flag.go -u 111 -pwd 222 -h 127.0.0.1 -port 222
user=111
pwd=222
host=127.0.0.1
port=222
$ go run go_flag.go -u=111 -pwd=222 -h=127.0.0.1 -port=222
user=111
pwd=222
host=127.0.0.1
port=222
flag 包使用指南
-
定义参数
使用flag包,首先定义待解析的命令行参数,也就是以“-” 开头的参数,比如上面的“-u -pwd”。 -help 不需要特别指定,可以自动处理。
func StringVar(p *string, name string, value string, usage string) { } func IntVar(p *int, name string, value int, usage string) { }
两个函数参数都有4个,分别是要接收的参数地址,命令行参数名称,默认值,提示字符串。
-
解析参数
flag使用前,必须首先解析。
flag.Parse()
-
使用参数
如上所示,可以直接使用
-
未解析参数
参数中如果有没有按照预定义的参数解析部分,通过
flag.Args()
即可获取,是一个字符串切片。
fmt.Println("其他参数:, flat.Args()")
需要注意的是,从第一个不能解析的参数开始,后面的所有参数都是无法解析的。即使后面的参数中含有预定义的参数。
package main
import (
"fmt"
"flag"
)
var b = flag.Bool("b", false, "布尔型参数")
var s = flag.String("s", "", "字符串类型参数")
func main() {
flag.Parse()
fmt.Println("-b", *b)
fmt.Println("-s", *s)
fmt.Println("其他参数", flag.Args())
}
不同参数,执行结果如下:
----------------
$ go run flag1.go
-b false
-s
其他参数 []
----------------
$ go run flag1.go -b
-b true
-s
其他参数 []
----------------
$ go run flag1.go -b -s woshishei other
-b true
-s woshishei
其他参数 [other]
----------------
age of /var/folders/jd/_nrr3p2x5pncw4y0trf_0bq40000gn/T/go-build1422013025/b001/exe/flag1:
-b 布尔型参数
-s string
字符串类型参数
----------------
$ go run flag1.go -b sss -s woshishei other
-b true
-s
其他参数 [sss -s woshishei other]
----------------