IM10-命令行解析
上一章的 IP 和 端口 都是写死的,那能不能像命令 nc 127.0.0.1 8088
那样,把 IP 和 端口 命令参数传进去呢?
这就用到了 flag
这个包了。
如果你想自己写一个像 ls、cd、tar
这样的命令,那一定要好好掌握 flag
包。
解析命令行其实有两种方法:
- 通过
os.Args
获得所有参数,在通过切片得到每一个参数
- 通过
flag
包获得
解析方法
os.Args
os.Args 是一个字符串切片 []string
,用法非常简单:
| package main
import (
"fmt"
"os"
)
func main() {
for i, arg := range os.Args {
fmt.Printf("args[%d] is %v \n", i, arg)
}
}
|
运行:
| $ go build -o echo_args
$ ./echo_args 1 2 B o i i
args[0] is ./echo_args
args[1] is 1
args[2] is 2
args[3] is B
args[4] is o
args[5] is i
args[6] is i
|
flag
flag 包提供了 T()
系列、TVar()
系列。
T()
系列基本格式:flag.T(参数名, 默认值, 帮助信息) *T
- 具体有以下几种:
flag.Bool()
flag.String()
flag.Int()
flag.Int64()
flag.Duration()
flag.Float64()
flag.Uint()
flag.Uint64()
TVat()
系列基本格式:flag.StringVar(&T, 参数名, 默认值, 帮助信息)
- 具体有以下几种:
flag.BoolVar()
flag.StringVar()
flag.IntVar()
flag.Int64Var()
flag.DurationVar()
flag.Float64Var()
flag.UintVar()
flag.Uint64Var()
- 区别:
T()
系列返回一个 T型指针,需要一个变量去承接
TVar()
系列不返回,变量是作为参数传进去的。
举例:
| func main() {
// T() 系列
name := flag.String("n", "Boii", "请输入名字")
// TVar() 系列
var sex string
flag.StringVar(&sex, "s", "男", "请输入性别")
flag.Parse() // 得调用 Parse 才能解析命令行参数
fmt.Println("name is", *name)
fmt.Println("sex is", sex)
}
|
运行:
| $ go build -o flag_args
$ ./flag_args -n Eva -s=女
name is Eva
sex is 女
|
flag 形式
通过 flag 包这两个系列接收的命令行参数,在命令中可以使用以下4种方式:
-flag xxx
-flag=xxx
(等号两边不能有空格,布尔类型参数必须用等号的方式)
--flag xxx
--flag=xxx
(等号两边不能有空格,布尔类型参数必须用等号的方式)
| $ ./flag_args -n Eva --s 女
$ ./flag_args -n=Eva --s=女
|
帮助信息
通过 -h、--h
或 -help、--help
可以获得帮助信息。
| $ ./flag_args --help
Usage of ./flag_args:
-n string
请输入名字 (default "Boii")
-s string
请输入性别 (default "男")
$ ./flag_args -h
Usage of ./flag_args:
-n string
请输入名字 (default "Boii")
-s string
请输入性别 (default "男")
|
改造客户端
说完两种解析方式,接下来开始让客户端具有解析功能
使用第一种os.Args
的方式:
| package main
import (
"os"
"log"
"strconv"
)
// $ ./client -ip 127.0.0.1 -port 8088
func main() {
// 读取参数
serverIP := os.Args[1]
serverPort, _ := strconv.Atoi(os.Args[2])
// 启动客户端连接服务器
client := NewClient(serverIP, serverPort)
if client == nil {
log.Println(">>>>> 连接服务器失败...")
return
}
log.Println(">>>>> 连接服务器成功...")
select {}
}
|
使用第二种flag
的方式:
| package main
import (
"flag"
"log"
)
var serverIP string
var serverPort int
// $ ./client -ip 127.0.0.1 -port 8088
func init() {
// 读取参数
flag.StringVar(&serverIP, "ip", "127.0.0.1", "设置服务器IP地址")
flag.IntVar(&serverPort, "port", 80, "设置服务器端口")
flag.Parse()
}
func main() {
// 启动客户端连接服务器
client := NewClient(serverIP, serverPort)
if client == nil {
log.Println(">>>>> 连接服务器失败...")
return
}
log.Println(">>>>> 连接服务器成功...")
select {}
}
|
这里将 flag
解析的部分放在 init()
函数中,因为读取命令行参数只会做一次,而且 init()
是先于 main()
运行的,所以比较规范。
编译运行
| $ go build -o client ./main.go ./client.go
$ ./client -ip 127.0.0.1 -port 8088
|