我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Golang开发命令行之flag包的使用方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Golang开发命令行之flag包的使用方法

1、命令行工具概述

日常命令行操作,相对应的众多命令行工具是提高生产力的必备工具,鼠标能够让用户更容易上手,降低用户学习成本。 而对于开发者,键盘操作模式能显著提升生产力,还有在一些专业工具中, 大量使用快捷键代替繁琐的鼠标操作,能够使开发人员更加专注于工作,提高效率,因为键盘操作模式更容易产生肌肉记忆

举个栗子:我司业务研发,前些年在我们的强力推动下(被迫)转向使用了 git 作为版本控制,开始使用的是图形化“小乌龟”工具。后续出现几次问题解决起来较麻烦后,推荐其使用原生的 git 命令行。如今,使用 git 命令行操作版本控制可谓 “一顿操作猛如虎......”

命令行(键盘)操作在很大程度上可以提高工作效率,与之相对应的是鼠标(触屏等)操作,这两种模式是目前的主流人机交互方式

设计一款命令行工具的开发语言可以选择原始的 shell 、甚至是更原始的语言 C ,更为容易上手且功能更多的有 node python golang

本文是基于 golang 开发命令行工具的开篇,主要是基于 golang 原生内置的、轻量的 flag 包实现,用 golang 设计命令行工具而不用 shell python 的原因这里就不做论述了

2、flag包介绍

flag 包用来解析命令行参数

相比简单的使用 os.Args 来获取命令行参数, flag 可以实现按照更为通用的命令行用法,例如 mysql -u root -p 123456 。其中 mysql 是命令行的名称即这个命令, -u-p 分别是这个命令的两个参数:用户名和密码,后面接着的是对应的参数值,有了参数的声明之后,两个参数可以互换位置,参数值也可以选填或按照缺省(默认)值进行指定

flag 包支持的命令行参数的类型有 bool int int64 uint uint64 float float64 string duration

即布尔值、整型、浮点型、字符串、时间段类型

3、flag包命令行参数的定义

定义 flag 命令行参数,用来接收命令行输入的参数值,一般有以下两种方法

flag.TypeVar():先定义参数(实际上是指针),再定义 flag.TypeVar 将命令行参数存储(绑定)到前面参数的值的指针(地址)


var name string
var age int
var height float64
var graduated bool
// &name 就是接收用户命令行中输入的-n后面的参数值
// 返回值是一个用来存储name参数的值的指针/地址
// 定义string类型命令行参数name,括号中依次是变量名、flag参数名、默认值、参数说明
flag.StringVar(&name, "n", "", "name参数,默认为空")
// 定义整型命令行参数age
flag.IntVar(&age,"a", 0, "age参数,默认为0")
// 定义浮点型命令行参数height
flag.Float64Var(&height,"h", 0, "height参数,默认为0")
// 定义布尔型命令行参数graduated
flag.BoolVar(&graduated,"g", false, "graduated参数,默认为false")


flag.Type():用短变量声明的方式定义参数类型及变量名


// 定义string类型命令行参数name,括号中依次是flag参数名、默认值、参数说明
namePtr := flag.String("n", "", "name参数,默认为空")
// 定义整型命令行参数age
age := flag.Int("a", 0, "age参数,默认为0")
// 定义浮点型命令行参数height
height := flag.Float64("h", 0, "height参数,默认为0")
// 定义布尔型命令行参数graduated
graduated:= flag.Bool("g", false, "graduated参数,默认为false")

4、flag包命令行参数解析

固定用法,定义好参数后,通过调用 flag.Parse() 来对命令行参数进行解析写入注册的 flag 里,进而解析获取参数值,通过查看源码中也是调用的 os.Args

源码路径 go/class="lazy" data-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:])
}

进而查看 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
}

真正解析参数的是 parseOne 方法(这里省略源码),结论是

  • 当遇到单独的一个 "-" 或不是 "-" 开始时,会停止解析
  • 遇到连续的两个 "-" 时,解析停止
  • 在终止符"-"之后停止

解析参数时,对于参数的指定方式一般有"-"、"--"、以及是否空格等方式,组合下来有如下几种方式

-flag xxx 空格和一个 - 符号
--flag xxx 空格和两个 - 符号
-flag=xxx 等号和一个 - 符号
--flag=xxx 等号和两个 - 符号

其中, -flag xxx 方式最为常用,如果参数是布尔型,只能用等号方式指定

5、flag包命令行帮助

flag 包默认会根据定义的命令行参数,在使用时如果不输入参数就打印对应的帮助信息

这样的帮助信息我们可以对其进行覆盖去改变默认的 Usage


package main

import (
    "flag"
    "fmt"
)

func main()  {
    var host string
    var port int
    var verbor bool
    var help bool
    // 绑定命令行参数与变量关系
    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()
    }
    // 解析命令行参数
    flag.Parse()
    if help {
        flag.Usage()
    } else {
        fmt.Println(host, port, verbor)
    }
}


6、flag定义短参数和长参数

简单来说,短参数和长参数,就是例如我们在使用某些命令时,查看命令版本可以输入 -V ,也可以输入 --version 。这种情况下, flag 并没有默认支持,但是可以通过可以两个选项共享同一个变量来实现,即通过给某个相同的变量设置不同的选项,参数在初始化的时候其顺序是不固定的,因此还需要保证其拥有相同的默认值


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 声明公共的常量,并在默认值以及帮助信息中去使用,这样就可以实现了

7、示例

实现计算字符串或目录下递归计算文件 md5 的命令,类似 linux md5sum 命令

其中利用 bufio 分批次读取文件,防止文件过大时造成资源占用高


package main

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

func md5reader(reader *bufio.Reader) string {  //
 hasher := md5.New()  // 定义MD5 hash计算器
 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)
  }
 }
}

编译生成二进制文件


➜  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

到此这篇关于Golang开发命令行之flag包的使用方法的文章就介绍到这了,更多相关Golang开发命令行之flag包的使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Golang开发命令行之flag包的使用方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Linux压缩打包命令的使用方法

本篇内容主要讲解“Linux压缩打包命令的使用方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux压缩打包命令的使用方法”吧!参数:-c :建立一个压缩文件的参数指令(create 的意
2023-06-13

Android开发之SQLite的使用方法

前言 SQLite是一种轻量级的小型数据库,虽然比较小,但是功能相对比较完善,一些常见的数据库基本功能也具有,在现在的嵌入式系统中使用该数据库的比较多,因为它占用系统资源很少。Android系统中也不例外,也是采用SQLite,本节中就学习
2022-06-06

node.js命令行使用的方法有哪些

在Node.js命令行中,可以使用以下方法:1. 执行JavaScript文件:使用`node`命令后跟要执行的JavaScript文件的路径,例如:`node app.js`。2. 进入REPL(交互式解释器)模式:在命令行中输入`nod
2023-08-16

详解golang执行Linux shell命令完整场景下的使用方法

目录1. 执行命令并获得输出结果2. 将stdout和stderr分别处理3. 异编程客栈步执行命令4. 执行时带上环境变量5. 预先检查命令是否存在6. 两个命令依次执行,管道通信7. 按行读取输出内容8. 获得exit code1. 执
2022-06-30

如何使用pip命令进行Python开发者必看的安装方法详解

Python开发者必看:pip命令安装方法详解引言:Python是一种广泛使用的高级编程语言,拥有庞大的开发者社区和生态系统。为了方便Python开发者管理和使用第三方库,Python提供了一个强大的包管理工具——pip。本文将详细解释p
如何使用pip命令进行Python开发者必看的安装方法详解
2024-01-18

Android入门之使用eclipse进行源码开发的方法

本文实例讲述了Android入门之使用eclipse进行源码开发的方法。分享给大家供大家参考,具体如下: 一、版本说明: 1. eclipse for javaEE 3.5.2 2. jdk1.6 3. adt12.0 4. linux/U
2022-06-06

win11使用命令行调出设置的方法

今天小编给大家分享一下win11使用命令行调出设置的方法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、首先我们右键点击“
2023-07-01

Python 使用pip在windows命令行中安装HDF reader包的操作方法

HDFreader包是一个常用来将.mat类型数据导入到python在这里插入代码片中使用的包,非常好用,今天介绍一下,如何在命令行中安装这个包,需要的朋友可以参考下
2022-12-15

使用shell脚本执行hive、sqoop命令的方法

1、test.sh脚本内容如下:#!/bin/bash#CURR_DATE=`date +"%Y-%m-%d %H:%M:%S"`------>不能使用 v_sql="insert into origin_ennenergy_ene
2022-06-04

在SQL Server中使用命令调用SSIS包的具体方法

在SQL Server中可以使用dtexec命令运行SSIS包(2005以上版本),当然也可以通过系统过程:xp_cmdshell调用dtexec运行SSIS包
2022-11-15

C#命令行参数解析库System.CommandLine的使用方法

这篇文章主要介绍了C#命令行参数解析库System.CommandLine的使用方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。命令行参数平常在日常的开发过程中,会经常用到
2023-06-15

MySQL使用命令行备份数据的方法详解

MySQL命令行备份详解通过mysqldump命令,可导出数据库结构和数据至SQL文件,并提供多种选项加快备份速度或确保数据一致性。此外,还可备份所有数据库或压缩备份文件。还原数据时,使用mysql命令从备份文件中导入。其他备份选项包括xtrabackup(在线热备份)、PerconaXtraBackup(增强功能)和pt-table-checksum(验证完整性)。制定全面的备份策略至关重要,包括定期备份频率、存储位置、数据恢复计划和备份文件测试。
MySQL使用命令行备份数据的方法详解
2024-04-02

深入探讨Python命令行参数的使用方法

全面解析Python命令行参数在开发Python程序时,我们经常需要从命令行中获取用户输入的参数。Python提供了很多方式来处理命令行参数,本文将全面解析这些方式,并给出具体的代码示例。sys.argvsys.argv是Python
深入探讨Python命令行参数的使用方法
2024-02-03

android开发教程之android的handler使用方法

Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title.首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示:代码如下:pack
2022-06-06

Windows 8 开发之摄像头的使用方法

1.更新项目中package.appmanifest 文件,本文让webcam和microphone可用。只需要在功能选项卡中勾选对应的框即可。如下图所示:如果不按照上面的设置,那么这些功能是不可以使用的,所以,确保首先设置好了。在Wind
2022-06-04

linux下安装oracle后使用命令行启动的方法

本篇内容主要讲解“linux下安装oracle后使用命令行启动的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux下安装oracle后使用命令行启动的方法”吧!代码如下:#su - o
2023-06-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录