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: flag
convenient command-line parsing.
Note: Several Conception Distinction
- Command-line arguments (or parameters): refers to the parameters provided to run the program
- Command-line parameters have been defined: refers to the procedure defined by the parameters of this form like flag.Xxx
- 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 flag
achieve 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 Xxx
may 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 receiver
pointer), 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 languages
obtained 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 -flag
this form, if bool type does not support -flag
this 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/BoolVar
the 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.conf
the 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 CommandLine
defined 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 -help
parameter (command given) but not defined (no code), the method returns ErrHelp
an 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 parseOne
method, we explain non-flag
and 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, nil
time, 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, -c
it will not be resolved correctly. Like in this example, "-" or build (and subsequent parameters), we call non-flag
parameters.
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 c
value
parseOne the next is a processing method -flag=x
in this form, then -flag
this form (bool type) (bool herein has been specially designed for), then -flag x
this 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-flag
parameters.
Arg(i int) 和 Args()、NArg()、NFlag()
Arg (i int) and the Args () these two methods is to obtain the non-flag
parameter; narG () obtained non-flag
number; (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.