Go in Flag packages.

This article Original Address: https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/edit/master/chapter13/13.1.md
while writing command line program (tools, server), command parameters parsing is a common demand. Various languages usually provide a method for parsing command line parameters or library to facilitate the programmers to use. If the command-line arguments purely to write their own code analysis for more complex, or very strenuous. Provided in the standard library go in a package: flagconvenient command-line parsing.

Note: Several Conception Distinction

  1. Command-line arguments (or parameters): refers to the parameters provided to run the program
  2. Command-line parameters have been defined: refers to the procedure defined by the parameters of this form like flag.Xxx
  3. Non flag (non-flag) command-line arguments (command line parameters or retained): explained later

Examples of Use

We nginx for example, the implementation of nginx -h, output is as follows:

nginx version: nginx/1.10.0
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/local/nginx/)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file

We flagachieve similar nginx this output, create a file nginx.go, reads as follows:

package main

import (
	"flag"
	"fmt"
	"os"
)

// 实际中应该用更好的变量名
var (
	h bool

	v, V bool
	t, T bool
	q    *bool

	s string
	p string
	c string
	g string
)

func init() {
	flag.BoolVar(&h, "h", false, "this help")

	flag.BoolVar(&v, "v", false, "show version and exit")
	flag.BoolVar(&V, "V", false, "show version and configure options then exit")

	flag.BoolVar(&t, "t", false, "test configuration and exit")
	flag.BoolVar(&T, "T", false, "test configuration, dump it and exit")

	// 另一种绑定方式
	q = flag.Bool("q", false, "suppress non-error messages during configuration testing")

	// 注意 `signal`。默认是 -s string,有了 `signal` 之后,变为 -s signal
	flag.StringVar(&s, "s", "", "send `signal` to a master process: stop, quit, reopen, reload")
	flag.StringVar(&p, "p", "/usr/local/nginx/", "set `prefix` path")
	flag.StringVar(&c, "c", "conf/nginx.conf", "set configuration `file`")
	flag.StringVar(&g, "g", "conf/nginx.conf", "set global `directives` out of configuration file")

	// 改变默认的 Usage
	flag.Usage = usage
}

func main() {
	flag.Parse()

	if h {
		flag.Usage()
	}
}

func usage() {
	fmt.Fprintf(os.Stderr, `nginx version: nginx/1.10.0
Usage: nginx [-hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
`)
	flag.PrintDefaults()
}

Performed: go run nginx.go -h, (or go build -o nginx && ./nginx -h) output is as follows:

nginx version: nginx/1.10.0
Usage: nginx [-hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -T	test configuration, dump it and exit
  -V	show version and configure options then exit
  -c file
    	set configuration file (default "conf/nginx.conf")
  -g directives
    	set global directives out of configuration file (default "conf/nginx.conf")
  -h	this help
  -p prefix
    	set prefix path (default "/usr/local/nginx/")
  -q	suppress non-error messages during configuration testing
  -s signal
    	send signal to a master process: stop, quit, reopen, reload
  -t	test configuration and exit
  -v	show version and exit

Carefully appreciated that the above example, if there is not understood, after reading the following explanation go back and look.

flag bag Overview

flag Package implements parsing command line parameters.

There are two ways to define flags

1) flag.Xxx (), which Xxxmay be Int, String like; Returns a pointer to the appropriate type, such as:

var ip = flag.Int("flagname", 1234, "help message for flagname")

2) flag.XxxVar (), the flag bound to a variable, such as:

var flagvar int
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")

Custom Value

In addition, you can create a custom flag, as long as the interface can be implemented flag.Value (claim receiverpointer), the flag at this time can be defined by:

flag.Var(&flagVal, "name", "help message for flagname")

For example, my favorite programming language parsing, we hope to resolve directly to the slice, we can define the following Value:

type sliceValue []string

func newSliceValue(vals []string, p *[]string) *sliceValue {
	*p = vals
	return (*sliceValue)(p)
}

func (s *sliceValue) Set(val string) error {
	*s = sliceValue(strings.Split(val, ","))
	return nil
}

func (s *sliceValue) Get() interface{} { return []string(*s) }

func (s *sliceValue) String() string { return strings.Join([]string(*s), ",") }

After so to use:

var languages []string
flag.Var(newSliceValue([]string{}, &languages), "slice", "I like programming `languages`")

By so -slice "go,php"passing the parameters in such a form languagesobtained it is [go, php].

Duration of this flag in the non-basic type of support used is similar in this way.

Parsing flag

After all the flag defined, by calling flag.Parse()for resolution.

The syntax of the command line flag can take three forms:

-flag // 只支持 bool 类型
-flag=x
-flag x // 只支持非 bool 类型

The third form which can only be used for non-bool type of flag, the reason is: If it does, then for this command cmd -x *, if there is a file name is: 0 or false intent will change and so on, the command of the ( the reason for this is because bool type support -flagthis form, if bool type does not support -flagthis form, you can type bool and other types of the same process. it is because of this, Parse (), the type of bool for a special treatment) . Default is provided -flag, the corresponding value is true, otherwise flag.Bool/BoolVarthe default value specified; if you want to display is set to false use -flag=false.

int type can be decimal, hexadecimal, octal, or even negative; bool type can be 1, 0, t, f, true, false, TRUE, FALSE, True, False. Duration can accept any type of time.ParseDuration can be resolved.

Types and functions

Before looking at the types and functions, look at the variables.

ErrHelp: The wrong type is used when the command-line parameters specified when · -help` but not defined.

Usage: This is a function that defines the output of all the command-line arguments and help information (usage message). In general, when an error parsing command line parameters, the function is called. We can specify your own Usage function, namely:flag.Usage = func(){}

function

go standard library, often do:

Definition of a type, a number of ways; for convenience, will instantiate an instance (generic) this type, so that it can directly use the method to call instance. For example: encoding / base64 and provides StdEncoding URLEncoding instance, use: base64.StdEncoding.Encode ()

Flag in the packet using similar methods, such as CommandLine examples, but were further encapsulated flag: to redefine methods FlagSet again, that is, provides a sequence of functions, and function simply call instantiated the FlagSet good example: CommandLine method. In this way, the user is so call:. Flag.Parse () instead of flag CommandLine.Parse (). (Go 1.2 from the CommandLine export, non previously exported)

Each function not described in detail herein, the type described in the process.

Types (data structures)

1)ErrorHandling

type ErrorHandling int

This type defines the error handling when the error parameter parsing mode. This defines three types of constants:

const (
	ContinueOnError ErrorHandling = iota
	ExitOnError
	PanicOnError
)

Three constants used in the method parseOne FlagSet source () of.

2)Flag

// A Flag represents the state of a flag.
type Flag struct {
	Name     string // name as it appears on command line
	Usage    string // help message
	Value    Value  // value as set
	DefValue string // default value (as text); for usage message
}

Flag type represents a flag state.

For example, for the command: ./nginx -c /etc/nginx.confthe corresponding code is:

flag.StringVar(&c, "c", "conf/nginx.conf", "set configuration `file`")

Examples of the Flag (can flag.Lookup("c")be obtained) corresponding to the value of each field:

&Flag{
	Name: c,
	Usage: set configuration file,
	Value: /etc/nginx.conf,
	DefValue: conf/nginx.conf,
}

3) FlagSet

// A FlagSet represents a set of defined flags.
type FlagSet struct {
	// Usage is the function called when an error occurs while parsing flags.
	// The field is a function (not a method) that may be changed to point to
	// a custom error handler.
	Usage func()

	name string // FlagSet 的名字。CommandLine 给的是 os.Args[0]
	parsed bool // 是否执行过 Parse()
	actual map[string]*Flag // 存放实际传递了的参数(即命令行参数)
	formal map[string]*Flag // 存放所有已定义命令行参数
	args []string // arguments after flags // 开始存放所有参数,最后保留 非 flag(non-flag)参数
	exitOnError bool // does the program exit if there's an error?
	errorHandling ErrorHandling // 当解析出错时,处理错误的方式
	output io.Writer // nil means stderr; use out() accessor
}

4) Value Interface

// Value is the interface to the dynamic value stored in a flag.
// (The default value is represented as a string.)
type Value interface {
	String() string
	Set(string) error
}

Parameter Type Value implement all required interfaces, flag package, as int, float, bool other implements the interface. With this interface, we can customize the flag. (Above specific examples have been given)

The main types of processes (including type instantiation)

flag is mainly FlagSet package type.

Examples of the way

NewFlagSet()Examples of FlagSet. Examples of predefined FlagSet CommandLinedefined manner:

// The default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)

Visible, the default FlagSet instance when parsing error will exit the program.

Because the field is not in FlagSet Export, FlagSet Example otherwise obtained, such as: FlagSet {} or new (FlagSet), it should be called Init () method, and to initialize ErrorHandling name, or the name is empty, as ErrorHandling ContinueOnError.

The method defined parameter flag

This sequence method has two forms, at the outset has been said the difference between the two approaches. These methods are used to define the parameters of a certain type of flag.

Analytical parameters (Parse)

func (f *FlagSet) Parse(arguments []string) error

Parsing flag defined in the parameter list. The method does not include a command name parameter arguments, i.e., it should be os.Args [1:]. In fact, flag.Parse()function did just that:

// 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:])
}

The method should be specific parameter value of the parameter after the flag was previously defined access calls.

If a -helpparameter (command given) but not defined (no code), the method returns ErrHelpan error. The default CommandLine, when Parse error will exit the program (ExitOnError).

For a better understanding, we look at the Parse(arguments []string)source code:

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:
			os.Exit(2)
		case PanicOnError:
			panic(err)
		}
	}
	return nil
}

Non-true method of resolution parameters derivation method parseOne.

Combined parseOnemethod, we explain non-flagand document bag in this sentence:

Flag parsing stops just before the first non-flag argument ("-" is a non-flag argument) or after the terminator "--".

We need to know when to stop parsing.

According to Parse () loop conditions for termination (without regard to analytical error), we know that when parseOne return false, niltime, Parse parsing terminated. We do not consider the normal completion of the analysis. ParseOne look at the source code found that two returns false, nil.

1) a first non-flag parameter

s := f.args[0]
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
	return false, nil
}

That is, when faced with a separate "-" or not "-" at the start, stop resolving. such as:

./nginx - -c 或 ./nginx build -c

In both cases, -cit will not be resolved correctly. Like in this example, "-" or build (and subsequent parameters), we call non-flagparameters.

2) two successive "-"

if s[1] == '-' {
	num_minuses++
	if len(s) == 2 { // "--" terminates the flags
		f.args = f.args[1:]
		return false, nil
	}
}

That is, when faced with consecutive two "-", the parsing stops.

Description: That's "-" and "-" position and "-c" This is the same. In other words, the following scenario is not here to say:

./nginx -c --

Here, "-" it will be treated as a cvalue

parseOne the next is a processing method -flag=xin this form, then -flagthis form (bool type) (bool herein has been specially designed for), then -flag xthis form, finally, examples of successful parses Flag actual map stored in the FlagSet in.

In addition, in parseOne in such a sentence:

f.args = f.args[1:]

That is, each successfully executed once parseOne, f.args one less. So, FlagSet the args last stay is that all non-flagparameters.

Arg(i int) 和 Args()、NArg()、NFlag()

Arg (i int) and the Args () these two methods is to obtain the non-flagparameter; narG () obtained non-flagnumber; (i.e. the number of sets of parameters) nFlag () to get the actual length FlagSet.

Visit / VisitAll

These two functions are used to access the actual and formal FlatSet the Flag, and specific access method is determined by the caller.

PrintDefaults ()

Print all defaults defined parameters (call VisitAll achieve), the default output to standard error, unless the output FlagSet designated (by SetOutput () setting)

Set(name, value string)

Setting a flag value (Flag by finds the corresponding name)

to sum up

Suggested Use: Although the above talked about so much, in general, we simply define flag, and then parse, just as an example of the beginning of the same.

If your project requires more advanced or complex command line parsing mode, you can use https://github.com/urfave/cli  or  https://github.com/spf13/cobra these two powerful library.

Guess you like

Origin www.cnblogs.com/MaxBaiSecurity/p/12651587.html