脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go语言中读取命令参数的几种方法总结

Go语言中读取命令参数的几种方法总结

2020-05-12 10:54谢小路 Golang

部署golang项目时难免要通过命令行来设置一些参数,那么在golang中如何操作命令行参数呢?那么下面这篇文章就来给大家介绍了关于Go语言中读取命令参数的几种方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,

前言

对于一名初学者来说,想要尽快熟悉 Go 语言特性,所以以操作式的学习方法为主,比如编写一个简单的数学计算器,读取命令行参数,进行数学运算。

本文讲述使用三种方式讲述 Go 语言如何接受命令行参数,并完成一个简单的数学计算,为演示方便,最后的命令行结果大概是这样的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# input
./calc add 1 2
# output
3
 
# input
./calc sub 1 2
# out
-1
 
# input
./calc mul 10 20
# out
200

使用的三种方式是:

  • 内置 os 包读取命令参数
  • 内置 flag 包读取命令参数
  • cli 框架读取命令参数

0. 已有历史经验

如果你熟悉 Python 、Shell 脚本,你可以比较下:

Python

?
1
2
3
4
5
6
7
import sys
 
args = sys.argv
 
# args 是一个列表
# 第一个值表示的是 文件名
# 除第一个之外,其他的值是接受的参数

Shell

?
1
2
3
4
5
6
7
8
9
10
11
12
if [ $# -ne 2 ]; then
 echo "Usage: $0 param1 pram2"
 exit 1
fi
name=$1
age=$2
 
echo $name
echo $age
# `$0` 表示文件名
# `$1` 表示第一个参数
# `$2` 表示第二个参数

能看出一些共性,接收参数,一般解析出来都是一个数组(列表、切片), 第一个元素表示的是文件名,剩余的参数表示接收的参数。

好,那么为了实现 “简单数学计算” 这个功能,读取命令行参数:比如 ./calc add 1 2

除文件名之外的第一个元素:解析为 进行数学运算的 操作,比如: add、sub、mul、sqrt
其余参数表示:进行操作的数值

注意:命令行读取的参数一般为字符串,进行数值计算需要进行数据类型转换

大概思路就是这样。

1. OS 获取命令行参数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
os.Args
 
# 为接受的参数,是一个切片
 
strconv.Atoi
 
# 将字符串数值转换为整型
 
strconv.Itoa
 
# 将整型转换为字符串
 
strconv.ParseFloat
 
# 将字符串数值转换为浮点型
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
var help = func () {
 fmt.Println("Usage for calc tool.")
 fmt.Println("====================================================")
 fmt.Println("add 1 2, return 3")
 fmt.Println("sub 1 2, return -1")
 fmt.Println("mul 1 2, return 2")
 fmt.Println("sqrt 2, return 1.4142135623730951")
}
 
 
func CalcByOs() error {
 args := os.Args
 if len(args) < 3 || args == nil {
 help()
 return nil
 }
 operate := args[1]
 switch operate {
 case "add":{
  rt := 0
  number_one, err1 := strconv.Atoi(args[2])
  number_two, err2 := strconv.Atoi(args[3])
  if err1 == nil && err2 == nil {
  rt = number_one + number_two
  fmt.Println("Result ", rt)
  }
 }
 case "sub":
 {
  rt := 0
  number_one, err1 := strconv.Atoi(args[2])
  number_two, err2 := strconv.Atoi(args[3])
  if err1 == nil && err2 == nil {
  rt += number_one - number_two
  fmt.Println("Result ", rt)
  }
 }
 case "mul":
 {
  rt := 1
  number_one, err1 := strconv.Atoi(args[2])
  number_two, err2 := strconv.Atoi(args[3])
  if err1 == nil && err2 == nil {
  rt = number_one * number_two
  fmt.Println("Result ", rt)
  }
 }
 case "sqrt":
 {
  rt := float64(0)
  if len(args) != 3 {
  fmt.Println("Usage: sqrt 2, return 1.4142135623730951")
  return nil
  }
  number_one, err := strconv.ParseFloat(args[2], 64)
  if err == nil {
  rt = math.Sqrt(number_one)
  fmt.Println("Result ", rt)
  }
 }
 default:
 help()
 
 }
 return nil
}

最后的效果大概是:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
./calc add 1 2
Result 3
 
====================
 
./calc sub 1 2
Result -1
 
====================
 
./calc mul 10 20
Result 200
 
===================
 
./calc sqrt 2
Result 1.4142135623730951

2. flag 获取命令行参数

flag 包比 os 读取参数更方便。可以自定义传入的参数的类型:比如字符串,整型,浮点型,默认参数设置等

基本的使用方法如下:

?
1
2
3
var operate string
 
flag.StringVar(&operate,"o", "add", "operation for calc")

# 解释

绑定 operate 变量, name="o", value="add" , usage="operation for calc"

也可以这样定义为指针变量

?
1
var operate := flag.String("o", "add", "operation for calc")

同时还可以自定义 flag 类型

所有变量注册之后,调用 flag.Parse() 来解析命令行参数, 如果是绑定变量的方式,直接使用变量进行操作,
如果使用指针变量型,需要 *operate 这样使用。

flag.Args() 表示接收的所有命令行参数集, 也是一个切片

?
1
2
3
for index, value := range flag.Args {
 fmt.Println(index, value)
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func CalcByFlag() error {
 var operation string
 var numberone float64
 var numbertwo float64
 flag.StringVar(&operation, "o", "add", "operation for this tool")
 flag.Float64Var(&numberone, "n1", 0, "The first number")
 flag.Float64Var(&numbertwo, "n2", 0, "The second number")
 flag.Parse()
 fmt.Println(numberone, numbertwo)
 if operation == "add" {
 rt := numberone + numbertwo
 fmt.Println("Result ", rt)
 } else if operation == "sub" {
 rt := numberone - numbertwo
 fmt.Println("Result ", rt)
 } else if operation == "mul" {
 rt := numberone * numbertwo
 fmt.Println("Result ", rt)
 } else if operation == "sqrt" {
 rt := math.Sqrt(numberone)
 fmt.Println("Result ", rt)
 } else {
 help()
 }
 return nil
}

最后的结果效果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
./calc -o add -n1 1 -n2 2
Result 3
 
=============================
 
./calc -o sub -n1 2 -n2 3
Result -1
 
============================
 
./calc -o mul -n1 10 -n2 20
Result 200
 
===========================
 
./calc -o sqrt -n1 2
Result 1.4142135623730951

3. CLI 框架

cli 是一款业界比较流行的命令行框架。

所以你首先需要安装:

?
1
go get github.com/urfave/cli
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 一个简单的示例如下:
package main
 
import (
 "fmt"
 "os"
 
 "github.com/urfave/cli"
)
 
func main() {
 app := cli.NewApp()
 app.Name = "boom"
 app.Usage = "make an explosive entrance"
 app.Action = func(c *cli.Context) error {
 fmt.Println("boom! I say!")
 return nil
 }
 
 app.Run(os.Args)
}

好,为实现 “简单数学计算” 的功能,我们应该怎么实现呢?

主要是 使用 框架中的 Flag 功能,对参数进行设置

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.Flags = []cli.Flag {
 cli.StringFlag{
 Name: "operation, o",
 Value: "add",
 Usage: "calc operation",
 },
 cli.Float64Flag{
 Name: "numberone, n1",
 Value: 0,
 Usage: "number one for operation",
 },
 cli.Float64Flag{
 Name: "numbertwo, n2",
 Value: 0,
 Usage: "number two for operation",
 },
}

能看出,我们使用了三个参数:operation、numberone、numbertwo

同时定义了参数的类型,默认值,以及别名(缩写)

那么在这个框架中如何实现参数的操作呢:主要是重写app.Action 方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app.Action = func(c *cli.Context) error {
 operation := c.String("operation")
 numberone := c.Float64("numberone")
 numbertwo := c.Float64("numbertwo")
 //fmt.Println(operation, numberone, numbertwo)
 if operation == "add" {
 rt := numberone + numbertwo
 fmt.Println("Result ", rt)
 } else if operation == "sub" {
 rt := numberone - numbertwo
 fmt.Println("Result ", rt)
 } else if operation == "mul" {
 rt := numberone * numbertwo
 fmt.Println("Result ", rt)
 } else if operation == "sqrt" {
 rt := math.Sqrt(numberone)
 fmt.Println("Result ", rt)
 } else {
 help()
 }
 return nil
}
 
# 对 operation 参数进行判断,执行的是那种运算,然后编写相应的运算操作
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
func CalcByCli(){
 app := cli.NewApp()
 app.Name = "calc with go"
 app.Usage = "calc tool operate by go"
 app.Version = "0.1.0"
 app.Flags = [] cli.Flag {
  cli.StringFlag{
   Name: "operation, o",
   Value: "add",
   Usage: "calc operation",
  },
  cli.Float64Flag{
   Name: "numberone, n1",
   Value: 0,
   Usage: "number one for operation",
  },
  cli.Float64Flag{
   Name: "numbertwo, n2",
   Value: 0,
   Usage: "number two for operation",
  },
 }
 app.Action = func(c *cli.Context) error {
  operation := c.String("operation")
  numberone := c.Float64("numberone")
  numbertwo := c.Float64("numbertwo")
  //fmt.Println(operation, numberone, numbertwo)
  if operation == "add" {
   rt := numberone + numbertwo
   fmt.Println("Result ", rt)
  } else if operation == "sub" {
   rt := numberone - numbertwo
   fmt.Println("Result ", rt)
  } else if operation == "mul" {
   rt := numberone * numbertwo
   fmt.Println("Result ", rt)
  } else if operation == "sqrt" {
   rt := math.Sqrt(numberone)
   fmt.Println("Result ", rt)
  } else {
   help()
  }
  return nil
 }
 app.Run(os.Args)
}

调用这个函数的最终效果如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
./calc -o add --n1 12 --n2 12
Result 24
 
===================================
 
./calc -o sub --n1 100 --n2 200
Result -100
 
===================================
 
./calc -o mul --n1 10 --n2 20
Result 200
 
===================================
 
./calc -o sqrt --n1 2
Result 1.4142135623730951

4 其他

知道如何读取命令行参数,就可以实现一些更有意思的事。

比如网上有许多免费的 API 接口,比如查询天气,查询农历的API 接口。

还有一些查询接口,比如有道云翻译接口,你可以实现翻译的功能。

或者扇贝的接口,实现查询单词的功能。

再比如一些音乐接口,实现音乐信息查询。

不一一列了。

下面实现一个调用免费的查询天气的接口实现命令行查询天气。

GO 如何进行 HTTP 访问?内置的 net/http 可以实现

一个简易的GET 操作如下:

?
1
2
3
4
5
6
7
8
9
func Requests(url string) (string, error) {
 response, err := http.Get(url)
 if err != nil {
  return "", err
 }
 defer response.Body.Close()
 body, _ := ioutil.ReadAll(response.Body)
 return string(body), nil
}

免费的 API URL 如下:

?
1
http://www.sojson.com/open/api/weather/json.shtml?city=北京

返回的结果是一个Json 格式的数据

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{
 "status": 200,
 "data": {
  "wendu": "29",
  "ganmao": "各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。",
  "forecast": [
   {
    "fengxiang": "南风",
    "fengli": "3-4级",
    "high": "高温 32℃",
    "type": "多云",
    "low": "低温 17℃",
    "date": "16日星期二"
   },
   {
    "fengxiang": "南风",
    "fengli": "微风级",
    "high": "高温 34℃",
    "type": "晴",
    "low": "低温 19℃",
    "date": "17日星期三"
   },
   {
    "fengxiang": "南风",
    "fengli": "微风级",
    "high": "高温 35℃",
    "type": "晴",
    "low": "低温 22℃",
    "date": "18日星期四"
   },
   {
    "fengxiang": "南风",
    "fengli": "微风级",
    "high": "高温 35℃",
    "type": "多云",
    "low": "低温 22℃",
    "date": "19日星期五"
   },
   {
    "fengxiang": "南风",
    "fengli": "3-4级",
    "high": "高温 34℃",
    "type": "晴",
    "low": "低温 21℃",
    "date": "20日星期六"
   }
  ],
  "yesterday": {
   "fl": "微风",
   "fx": "南风",
   "high": "高温 28℃",
   "type": "晴",
   "low": "低温 15℃",
   "date": "15日星期一"
  },
  "aqi": "72",
  "city": "北京"
 },
 "message": "OK"
}

所以我们的任务就是传入 “城市” 的名称,再对返回的 Json 数据解析。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
 
import (
  "fmt"
  "os"
 "encoding/json"
  "github.com/urfave/cli"
  "net/http"
  "io/ioutil"
  //"github.com/modood/table"
)
type Response struct {
  Status int `json:"status"`
  CityName string `json:"city"`
  Data  Data `json:"data"`
  Date  string `json:"date"`
  Message string `json:"message"`
  Count int `json:"count"`
}
 
type Data struct {
  ShiDu  string `json:"shidu"`
  Quality string `json:"quality"`
  Ganmao string `json:"ganmao"`
  Yesterday Day `json:"yesterday"`
  Forecast []Day `json:"forecast"`
}
 
type Day struct {
  Date string `json:"date"`
  Sunrise string `json:"sunrise"`
  High string `json:"high"`
  Low  string `json:"low"`
  Sunset string `json:"sunset"`
  Aqi  float32 `json:"aqi"`
  Fx  string `json:"fx"`
  Fl  string `json:"fl"`
  Type string `json:"type"`
  Notice string `json:"notice"`
}
 
func main() {
  const apiURL = "http://www.sojson.com/open/api/weather/json.shtml?city="
  app := cli.NewApp()
  app.Name = "weather-cli"
  app.Usage = "天气预报小程序"
 
  app.Flags = []cli.Flag{
    cli.StringFlag{
      Name: "city, c",
      Value: "上海",
      Usage: "城市中文名",
    },
    cli.StringFlag{
      Name: "day, d",
      Value: "今天",
      Usage: "可选: 今天, 昨天, 预测",
    },
    cli.StringFlag{
      Name: "Author, r",
      Value: "xiewei",
      Usage: "Author name",
    },
  }
 
  app.Action = func(c *cli.Context) error {
    city := c.String("city")
    day := c.String("day")
 
    var body, err = Requests(apiURL + city)
    if err != nil {
      fmt.Printf("err was %v", err)
      return nil
    }
 
    var r Response
    err = json.Unmarshal([]byte(body), &r)
    if err != nil {
      fmt.Printf("\nError message: %v", err)
      return nil
    }
    if r.Status != 200 {
      fmt.Printf("获取天气API出现错误, %s", r.Message)
      return nil
    }
    Print(day, r)
    return nil
  }
  app.Run(os.Args)
 
}
 
 
func Print(day string, r Response) {
  fmt.Println("城市:", r.CityName)
  if day == "今天" {
    fmt.Println("湿度:", r.Data.ShiDu)
    fmt.Println("空气质量:", r.Data.Quality)
    fmt.Println("温馨提示:", r.Data.Ganmao)
  } else if day == "昨天" {
    fmt.Println("日期:", r.Data.Yesterday.Date)
    fmt.Println("温度:", r.Data.Yesterday.Low, r.Data.Yesterday.High)
    fmt.Println("风量:", r.Data.Yesterday.Fx, r.Data.Yesterday.Fl)
    fmt.Println("天气:", r.Data.Yesterday.Type)
    fmt.Println("温馨提示:", r.Data.Yesterday.Notice)
  } else if day == "预测" {
    fmt.Println("====================================")
    for _, item := range r.Data.Forecast {
      fmt.Println("日期:", item.Date)
      fmt.Println("温度:", item.Low, item.High)
      fmt.Println("风量:", item.Fx, item.Fl)
      fmt.Println("天气:", item.Type)
      fmt.Println("温馨提示:", item.Notice)
      fmt.Println("====================================")
    }
  } else {
    fmt.Println("...")
  }
 
}
func Requests(url string) (string, error) {
  response, err := http.Get(url)
  if err != nil {
    return "", err
  }
  defer response.Body.Close()
  body, _ := ioutil.ReadAll(response.Body)
  return string(body), nil
}

最终的效果大概如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
./weather -c 上海
 
城市: 上海
湿度: 80%
空气质量: 轻度污染
温馨提示: 儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼
 
 
================================
./weaather -c 上海 -d 昨天
 
城市: 上海
日期: 28日星期二
温度: 低温 12.0℃ 高温 19.0℃
风量: 西南风 <3级
天气: 小雨
温馨提示: 雾蒙蒙的雨天,最喜欢一个人听音乐

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.jianshu.com/p/548adff0d10d

延伸 · 阅读

精彩推荐
  • Golanggolang json.Marshal 特殊html字符被转义的解决方法

    golang json.Marshal 特殊html字符被转义的解决方法

    今天小编就为大家分享一篇golang json.Marshal 特殊html字符被转义的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    李浩的life12792020-05-27
  • Golanggo日志系统logrus显示文件和行号的操作

    go日志系统logrus显示文件和行号的操作

    这篇文章主要介绍了go日志系统logrus显示文件和行号的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang 通过ssh代理连接mysql的操作

    golang 通过ssh代理连接mysql的操作

    这篇文章主要介绍了golang 通过ssh代理连接mysql的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    a165861639710342021-03-08
  • GolangGolang通脉之数据类型详情

    Golang通脉之数据类型详情

    这篇文章主要介绍了Golang通脉之数据类型,在编程语言中标识符就是定义的具有某种意义的词,比如变量名、常量名、函数名等等,Go语言中标识符允许由...

    4272021-11-24
  • Golanggo语言制作端口扫描器

    go语言制作端口扫描器

    本文给大家分享的是使用go语言编写的TCP端口扫描器,可以选择IP范围,扫描的端口,以及多线程,有需要的小伙伴可以参考下。 ...

    脚本之家3642020-04-25
  • Golanggolang如何使用struct的tag属性的详细介绍

    golang如何使用struct的tag属性的详细介绍

    这篇文章主要介绍了golang如何使用struct的tag属性的详细介绍,从例子说起,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看...

    Go语言中文网11352020-05-21
  • GolangGolang中Bit数组的实现方式

    Golang中Bit数组的实现方式

    这篇文章主要介绍了Golang中Bit数组的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    天易独尊11682021-06-09
  • Golanggolang的httpserver优雅重启方法详解

    golang的httpserver优雅重启方法详解

    这篇文章主要给大家介绍了关于golang的httpserver优雅重启的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    helight2992020-05-14