最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang開發(fā)命令行之flag包的使用方法

 更新時(shí)間:2021年10月18日 15:33:44   作者:山山仙人博客  
這篇文章主要介紹Golang開發(fā)命令行及flag包的使用方法,日常命令行操作,相對(duì)應(yīng)的眾多命令行工具是提高生產(chǎn)力的必備工具,本文圍繞該內(nèi)容展開話題,需要的朋友可以參考一下

1、命令行工具概述

日常命令行操作,相對(duì)應(yīng)的眾多命令行工具是提高生產(chǎn)力的必備工具,鼠標(biāo)能夠讓用戶更容易上手,降低用戶學(xué)習(xí)成本。 而對(duì)于開發(fā)者,鍵盤操作模式能顯著提升生產(chǎn)力,還有在一些專業(yè)工具中, 大量使用快捷鍵代替繁瑣的鼠標(biāo)操作,能夠使開發(fā)人員更加專注于工作,提高效率,因?yàn)殒I盤操作模式更容易產(chǎn)生肌肉記憶

舉個(gè)栗子:我司業(yè)務(wù)研發(fā),前些年在我們的強(qiáng)力推動(dòng)下(被迫)轉(zhuǎn)向使用了 git 作為版本控制,開始使用的是圖形化“小烏龜”工具。后續(xù)出現(xiàn)幾次問題解決起來較麻煩后,推薦其使用原生的 git 命令行。如今,使用 git 命令行操作版本控制可謂 “一頓操作猛如虎......”

命令行(鍵盤)操作在很大程度上可以提高工作效率,與之相對(duì)應(yīng)的是鼠標(biāo)(觸屏等)操作,這兩種模式是目前的主流人機(jī)交互方式

設(shè)計(jì)一款命令行工具的開發(fā)語言可以選擇原始的 shell 、甚至是更原始的語言 C ,更為容易上手且功能更多的有 node 、 python golang

本文是基于 golang 開發(fā)命令行工具的開篇,主要是基于 golang 原生內(nèi)置的、輕量的 flag 包實(shí)現(xiàn),用 golang 設(shè)計(jì)命令行工具而不用 shell 、 python 的原因這里就不做論述了

2、flag包介紹

flag 包用來解析命令行參數(shù)

相比簡單的使用 os.Args 來獲取命令行參數(shù), flag 可以實(shí)現(xiàn)按照更為通用的命令行用法,例如 mysql -u root -p 123456 。其中 mysql 是命令行的名稱即這個(gè)命令, -u-p 分別是這個(gè)命令的兩個(gè)參數(shù):用戶名和密碼,后面接著的是對(duì)應(yīng)的參數(shù)值,有了參數(shù)的聲明之后,兩個(gè)參數(shù)可以互換位置,參數(shù)值也可以選填或按照缺省(默認(rèn))值進(jìn)行指定

flag 包支持的命令行參數(shù)的類型有 bool int 、 int64 、 uint 、 uint64 float float64 、 string duration

即布爾值、整型、浮點(diǎn)型、字符串、時(shí)間段類型

3、flag包命令行參數(shù)的定義

定義 flag 命令行參數(shù),用來接收命令行輸入的參數(shù)值,一般有以下兩種方法

flag.TypeVar():先定義參數(shù)(實(shí)際上是指針),再定義 flag.TypeVar 將命令行參數(shù)存儲(chǔ)(綁定)到前面參數(shù)的值的指針(地址)

var name string
var age int
var height float64
var graduated bool
// &name 就是接收用戶命令行中輸入的-n后面的參數(shù)值
// 返回值是一個(gè)用來存儲(chǔ)name參數(shù)的值的指針/地址
// 定義string類型命令行參數(shù)name,括號(hào)中依次是變量名、flag參數(shù)名、默認(rèn)值、參數(shù)說明
flag.StringVar(&name, "n", "", "name參數(shù),默認(rèn)為空")
// 定義整型命令行參數(shù)age
flag.IntVar(&age,"a", 0, "age參數(shù),默認(rèn)為0")
// 定義浮點(diǎn)型命令行參數(shù)height
flag.Float64Var(&height,"h", 0, "height參數(shù),默認(rèn)為0")
// 定義布爾型命令行參數(shù)graduated
flag.BoolVar(&graduated,"g", false, "graduated參數(shù),默認(rèn)為false")


flag.Type():用短變量聲明的方式定義參數(shù)類型及變量名

// 定義string類型命令行參數(shù)name,括號(hào)中依次是flag參數(shù)名、默認(rèn)值、參數(shù)說明
namePtr := flag.String("n", "", "name參數(shù),默認(rèn)為空")
// 定義整型命令行參數(shù)age
age := flag.Int("a", 0, "age參數(shù),默認(rèn)為0")
// 定義浮點(diǎn)型命令行參數(shù)height
height := flag.Float64("h", 0, "height參數(shù),默認(rèn)為0")
// 定義布爾型命令行參數(shù)graduated
graduated:= flag.Bool("g", false, "graduated參數(shù),默認(rèn)為false")

4、flag包命令行參數(shù)解析

固定用法,定義好參數(shù)后,通過調(diào)用 flag.Parse() 來對(duì)命令行參數(shù)進(jìn)行解析寫入注冊(cè)的 flag 里,進(jìn)而解析獲取參數(shù)值,通過查看源碼中也是調(diào)用的 os.Args

源碼路徑 go/src/flag/flag.go

// Parse parses the command-line flags from os.Args[1:]. Must be called
// after all flags are defined and before flags are accessed by the program.
func Parse() {
 // Ignore errors; CommandLine is set for ExitOnError.
 CommandLine.Parse(os.Args[1:])
}

進(jìn)而查看 Parse 方法的源碼

func (f *FlagSet) Parse(arguments []string) error {
 f.parsed = true
 f.args = arguments
 for {
  seen, err := f.parseOne()
  if seen {
   continue
  }
  if err == nil {
   break
  }
  switch f.errorHandling {
  case ContinueOnError:
   return err
  case ExitOnError:
   if err == ErrHelp {
    os.Exit(0)
   }
   os.Exit(2)
  case PanicOnError:
   panic(err)
  }
 }
 return nil
}

真正解析參數(shù)的是 parseOne 方法(這里省略源碼),結(jié)論是

  • 當(dāng)遇到單獨(dú)的一個(gè) "-" 或不是 "-" 開始時(shí),會(huì)停止解析
  • 遇到連續(xù)的兩個(gè) "-" 時(shí),解析停止
  • 在終止符"-"之后停止

解析參數(shù)時(shí),對(duì)于參數(shù)的指定方式一般有"-"、"--"、以及是否空格等方式,組合下來有如下幾種方式

-flag xxx 空格和一個(gè) - 符號(hào)
--flag xxx 空格和兩個(gè) - 符號(hào)
-flag=xxx 等號(hào)和一個(gè) - 符號(hào)
--flag=xxx 等號(hào)和兩個(gè) - 符號(hào)

其中, -flag xxx 方式最為常用,如果參數(shù)是布爾型,只能用等號(hào)方式指定

5、flag包命令行幫助

flag 包默認(rèn)會(huì)根據(jù)定義的命令行參數(shù),在使用時(shí)如果不輸入?yún)?shù)就打印對(duì)應(yīng)的幫助信息

這樣的幫助信息我們可以對(duì)其進(jìn)行覆蓋去改變默認(rèn)的 Usage

package main

import (
    "flag"
    "fmt"
)

func main()  {
    var host string
    var port int
    var verbor bool
    var help bool
    // 綁定命令行參數(shù)與變量關(guān)系
    flag.StringVar(&host, "H", "127.0.0.1", "ssh host")
    flag.IntVar(&port, "P", 22, "ssh port")
    flag.BoolVar(&verbor, "v", false, "detail log")
    flag.BoolVar(&help, "h", false, "help")
    // 自定義-h
    flag.Usage = func() {
        fmt.Println(`
Usage: flag [-H addr] [-p port] [-v]

Options: 
    `)
        flag.PrintDefaults()
    }
    // 解析命令行參數(shù)
    flag.Parse()
    if help {
        flag.Usage()
    } else {
        fmt.Println(host, port, verbor)
    }
}
/*
➜  go run flag_args.go -h

Usage: flag [-H addr] [-p port] [-v]

Options:

  -H string
        ssh host (default "127.0.0.1")
  -P int
        ssh port (default 22)
  -h    help
  -v    detail log
 */

6、flag定義短參數(shù)和長參數(shù)

簡單來說,短參數(shù)和長參數(shù),就是例如我們?cè)谑褂媚承┟顣r(shí),查看命令版本可以輸入 -V ,也可以輸入 --version 。這種情況下, flag 并沒有默認(rèn)支持,但是可以通過可以兩個(gè)選項(xiàng)共享同一個(gè)變量來實(shí)現(xiàn),即通過給某個(gè)相同的變量設(shè)置不同的選項(xiàng),參數(shù)在初始化的時(shí)候其順序是不固定的,因此還需要保證其擁有相同的默認(rèn)值

package main

import (
  "fmt"
  "flag"
)

var logLevel string

func init() {
  const (
    defaultLogLevel = "DEBUG"
    usage = "set log level"
  )
  flag.StringVar(&logLevel, "log_level", defaultLogLevel, usage)
  flag.StringVar(&logLevel, "l", defaultLogLevel, usage + "(shorthand)")
}

func main() {
  flag.Parse()
  fmt.Println("log level:", logLevel)
}

通過 const 聲明公共的常量,并在默認(rèn)值以及幫助信息中去使用,這樣就可以實(shí)現(xiàn)了

7、示例

實(shí)現(xiàn)計(jì)算字符串或目錄下遞歸計(jì)算文件 md5 的命令,類似 linux md5sum 命令

其中利用 bufio 分批次讀取文件,防止文件過大時(shí)造成資源占用高

package main

import (
 "bufio"
 "crypto/md5"
 "flag"
 "fmt"
 "io"
 "os"
 "strings"
)

func md5reader(reader *bufio.Reader) string {  //
 hasher := md5.New()  // 定義MD5 hash計(jì)算器
 bytes := make([]byte, 1024*1024*10)  // 分批次讀取文件

 for {
  n, err := reader.Read(bytes)
  if err != nil {
   if err != io.EOF {
    return ""
   }
   break
  } else {
   hasher.Write(bytes[:n])
  }
 }
 return fmt.Sprintf("%x", hasher.Sum(nil))
}

func md5file(path string) (string, error) {
 file, err := os.Open(path)
 if err != nil {
  return "", err
 } else {
  defer file.Close()
  return md5reader(bufio.NewReader(file)), nil
 }
}

func md5str(txt string) (string, error) {
 return md5reader(bufio.NewReader(strings.NewReader(txt))), nil
 //return fmt.Sprintf("%x", md5.Sum([]byte(txt)))
}

func main()  {
 txt := flag.String("s", "", "md5 txt")
 path := flag.String("f", "", "file path")
 help := flag.Bool("h", false, "help")
 flag.Usage = func() {
  fmt.Println(`
Usage: md5 [-s 123abc] [-f path]
Options:
  `)
  flag.PrintDefaults()
 }
 flag.Parse()
 if *help || *txt == "" && *path == "" {
  flag.Usage()
 } else {
  var md5 string
  var err error
  if *path != "" {
   md5, err = md5file(*path)
  } else {
   md5, err = md5str(*txt)
  }
  if err != nil {
   fmt.Println(err)
  } else {
   fmt.Println(md5)
  }
 }
}

編譯生成二進(jìn)制文件

➜  go build -o md5go -x md5_bufio.go
➜  ll md5go 
-rwxr-xr-x  1 ssgeek  staff   1.9M Oct 2 00:54 md5go


測試使用

➜  ./md5go -h             

Usage: md5 [-s 123abc] [-f path]
Options:
                
  -f string
        file path
  -h    help
  -s string
        md5 txt
➜  ./md5go -s 123456
e10adc3949ba59abbe56e057f20f883e
➜  ./md5go -f md5_bufio.go
8607a07cbb98cec0e9abe14b0db0bee6

到此這篇關(guān)于Golang開發(fā)命令行之flag包的使用方法的文章就介紹到這了,更多相關(guān)Golang開發(fā)命令行之flag包的使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang 接口嵌套實(shí)現(xiàn)復(fù)用的操作

    golang 接口嵌套實(shí)現(xiàn)復(fù)用的操作

    這篇文章主要介紹了golang 接口嵌套實(shí)現(xiàn)復(fù)用的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 基于原生Go語言開發(fā)一個(gè)博客系統(tǒng)

    基于原生Go語言開發(fā)一個(gè)博客系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了如何基于原生Go語言開發(fā)一個(gè)簡單的博客系統(tǒng),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • golang中import cycle not allowed解決的一種思路

    golang中import cycle not allowed解決的一種思路

    這篇文章主要給大家介紹了關(guān)于golang中import cycle not allowed解決的一種思路,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • Go中的動(dòng)態(tài)速率限制有效控制流量

    Go中的動(dòng)態(tài)速率限制有效控制流量

    這篇文章主要為大家介紹了Go中的動(dòng)態(tài)速率限制有效控制流量,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Go語言中三種不同md5計(jì)算方式的性能比較

    Go語言中三種不同md5計(jì)算方式的性能比較

    md5計(jì)算在我們?nèi)粘9ぷ鞯臅r(shí)候經(jīng)常能遇到,下面這篇文章主要介紹了Go語言中三種不同md5計(jì)算方式的性能比較,需要的朋友可以參考借鑒,下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-01-01
  • go語言中iota和左移右移的使用說明

    go語言中iota和左移右移的使用說明

    這篇文章主要介紹了go語言中iota和左移右移的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go語言中的原子操作使用詳解

    Go語言中的原子操作使用詳解

    這篇文章主要介紹了Go語言中的原子操作使用詳解的相關(guān)資料,需要的朋友可以參考下
    2023-08-08
  • Go語言使用Buffer實(shí)現(xiàn)高性能處理字節(jié)和字符

    Go語言使用Buffer實(shí)現(xiàn)高性能處理字節(jié)和字符

    在?Go?中,bytes.Buffer?是一個(gè)非常高效的類型,用于處理字節(jié)數(shù)據(jù)的讀寫操作,本文將詳細(xì)介紹一下如何使用Buffer實(shí)現(xiàn)高性能處理字節(jié)和字符,有需要的小伙伴可以了解下
    2025-01-01
  • Golang無限緩存channel的設(shè)計(jì)與實(shí)現(xiàn)解析

    Golang無限緩存channel的設(shè)計(jì)與實(shí)現(xiàn)解析

    這篇文章主要為大家介紹了Golang無限緩存channel的設(shè)計(jì)與實(shí)現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法

    Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法

    包(package)是多個(gè)Go源碼的集合,是一種高級(jí)的代碼復(fù)用方案,下面這篇文章主要給大家介紹了關(guān)于Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06

最新評(píng)論

双城市| 开原市| 姜堰市| 都匀市| 奈曼旗| 陈巴尔虎旗| 萍乡市| 枣庄市| 高平市| 九龙县| 溧水县| 阿坝| 旬邑县| 玉林市| 屏山县| 嘉祥县| 陈巴尔虎旗| 南城县| 乌拉特后旗| 讷河市| 米易县| 积石山| 耒阳市| 辽宁省| 兴业县| 临夏县| 揭西县| 新绛县| 新建县| 德令哈市| 襄城县| 巴青县| 安图县| 蒙阴县| 高州市| 鹿泉市| 开原市| 青州市| 内黄县| 盐亭县| 遵义市|