zoukankan      html  css  js  c++  java
  • 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 如下:

    返回的结果是一个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() {
      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(" Error 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级
    天气: 小雨
    温馨提示: 雾蒙蒙的雨天,最喜欢一个人听音乐

    总结

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

  • 相关阅读:
    LC 面试题56
    AspNet 执行存储过程带参数 and Entity Framework 之存储过程篇
    SQL中Charindex和Oracle中对应的函数Instr
    Spring MVC遭遇checkbox的问题解决方案
    Spring MVC 的 multipartResolver 不能同iWebOffice2006 共同使用
    Spring CommonsMultipartResolver 上传文件
    解决自定义文件上传处理与Spring MultipartResolver的冲突问题
    GooFlow
    js判断undefined类型
    mybatis generator tools配置文件解析
  • 原文地址:https://www.cnblogs.com/lgj8/p/12088793.html
Copyright © 2011-2022 走看看