Flag of the Golang standard library

Source: Internet
Author: User

It was mentioned that there were no examples and no idea what was being said. So, for the sake of a better understanding, an example has been deliberately added. In fact, this article is more about the principle of flag implementation, coupled with the example, it is better to know how to use. It is recommended to read the corresponding section of the book "Go Language Standard library": flag– command-line argument parsing.

Parsing command Arguments is a common requirement when writing command-line programs (Tools, servers). Various languages typically provide methods or libraries that parse command-line arguments for easy use by programmers. If the command line parameters are purely self-written code parsing, for more complex, it is very laborious. A package is available in the Go Standard library: Flag for easy command-line parsing.

Note: Distinguish several concepts
1) command-line arguments (or parameters): refers to the parameters provided by the running program
2) defined command line arguments: Refers to the program through flag. XXX and other parameters defined by this form
3) Non-flag (non-flag) command-line arguments (or reserved command-line arguments): explained later

First, use the example
We take nginx as an example, execute nginx-h, the 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 implement this output like nginx through ' flag ', creating a file Nginx.go with the following:

Package Main
Import (

"Flag"

"FMT"

"OS"

)

In practice, you should use a better variable name
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")



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")



Another way to bind

Q = flag. Bool ("Q", False, "suppress NON-ERROR messages during configuration testing")



Note ' Signal '. The default is-s string, after having ' signal ', becomes-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")



Change the default 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 ()

}
Execute: 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 understand the above example, if you do not understand, read the explanations below and then look back.

Ii. Overview of the flag package
The flag package implements the parsing of command-line arguments.

There are two ways of defining flags:

1) flag. xxx (), where xxx can be int, string, and so on; Returns a pointer of the appropriate type, such as:
var IP = flag. Int ("FlagName", 1234, "help message for FlagName")
2) flag. Xxxvar (), bind flag to a variable, such as:

var Flagvar int
Flag. Intvar (&flagvar, "FlagName", 1234, "help message for FlagName")
Alternatively, you can create a custom flag, as long as you implement flag. Value interface (requires receiver to be a pointer), this flag can be defined as follows:

Flag. Var (&flagval, "name", "Help message for FlagName")
For example, to parse a programming language that I like, and we want to parse directly into 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), ",")}
You can then use this:
var languages []string
Flag. Var (Newslicevalue ([]string{}, &languages), "Slice", "I like programming ' languages '")
This way, by-slice "go,php" to pass the parameters, languages gets [go, PHP].

This type of non-basic support for Duration is used in flag in the same way.

After all the flag definitions are complete, you can call flag. Parse () to parse.

The syntax of the command-line flag is in the following three ways:
-flag//only BOOL type supported
-flag=x
-flag x//only supports non-bool types

The third form can only be used for flags of non-bool type, because: if supported, then for such a command cmd-x *, if there is a file name is: 0 or FALSE, then the original intention of the command will change (this is because the bool type supports-flag this form, If the bool type does not support-flag this form, the bool type can be treated as if it were other types. Because of this, the bool type is specially treated in Parse (). By default,-flag is provided, and the corresponding value is true, otherwise flag. The default value specified in Bool/boolvar, or-flag=false if you want the display to be set to false.

The int type can be decimal, 16 binary, octal, or even negative; the bool type can be 1, 0, T, F, True, False, True, False, True, false. Duration can accept any type that time.parseduration can parse

Iii. Types and functions
Before you look at the types and functions, look at the variables
Errhelp: The error type is used when the command line specifies a-help parameter but is not defined.
Usage: This is a function that outputs all defined command-line parameters and help information (usage message). In general, the function is called when the command-line argument resolves an error. We can specify our own usage function: flag. Usage = Func () {}

1. Functions
In the Go standard library, do this often:

Defines a type, provides many methods, and, for ease of use, instantiates an instance of that type (common) so that the method can be called directly using the instance. For example: Encoding/base64 provides stdencoding and urlencoding instances, when used: Base64. Stdencoding.encode ()

Further encapsulation is carried out in the flag package: The Flagset method is redefined again, which provides a sequence of functions, and the function simply invokes the Flagset instance that has been instantiated: CommandLine method, This commandline instance does not require export. In this way, the user calls this: flag. Parse () instead of Flag.commandLine.Parse (). (Go 1.2 version changed to CommandLine)

Each function is not described in detail here, as described in the type method.

2. Type (data structure)
1) errorhandling
Type errorhandling int
This type defines how error handling is defined when a parameter parsing error occurs. Three constants of this type:

Const (

ContinueOnError errorhandling = Iota

Exitonerror

Paniconerror

)
The three constants are used in the Flagset method Parseone () of the source code.

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

}
The flag type represents the state of a flag.

For example: Autogo-f abc.txt, Code flag. String ("F", "a.txt", "usage"), the corresponding value of the flag instance (which can be obtained by flag.lookup ("F") is: F, usage, abc.txt, a.txt.

3) Flagset

A flagset represents a set of defined flags.
Type Flagset struct {

Usage is the function called if an error occurs while parsing flags.

The field is a function (not a method), which is changed

A custom error handler.

Usage func ()

Name of string//Flagset. The CommandLine gives the OS. Args[0]

parsed bool//Have you performed the parse ()

Actual Map[string]*flag//store the arguments that were actually passed (that is, command-line arguments)

Formal Map[string]*flag//store all defined command line parameters

args []string//arguments after flags//starts to store all parameters and finally retains non-flag (non-flag) parameters

exitonerror BOOL//Does the program exit if there's an error?

Errorhandling errorhandling//When parsing an error, how to handle the error

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
}
All parameter types need to implement the value interface, which is implemented in the flag packet for int, float, bool, and so on. With this interface, we can customize the flag

Iv. main types of methods (including type instantiation)
The flag packet is primarily of the flagset type.

1, the way of instantiation
Newflagset () is used to instantiate the Flagset. Predefined Flagset instance CommandLine are defined as follows:

The default set of command-line flags, parsed from OS. Args.
var CommandLine = newflagset (OS. Args[0], Exitonerror)
As can be seen, the default Flagset instance exits the program when parsing an error.

Since the fields in Flagset do not have export, other ways to obtain the Flagset instance, such as: flagset{} or New (Flagset), you should call the Init () method, initialize name and errorhandling.

2. Define the flag parameter method
The method of this sequence has two forms, which at the beginning have been said to differ in two ways. These methods are used to define a flag parameter of a certain type.

3. Parsing parameters (parse)
Func (f *flagset) Parse (arguments []string) error
Resolves the defined flag from the list of parameters. The parameter arguments does not include the command name, which should be the OS. Args[1:].
In fact, flag. This is what the Parse () function does:
Parse parses the command-line flags from OS.  Args[1:]. Must be called
After all flags is defined and before flags is accessed by the program.
Func Parse () {
Ignore errors; CommandLine is set for Exitonerror.
Commandline.parse (OS. Args[1:])
}
The method should be called before the flag parameter is defined and the specific parameter value is accessed.

If the-help parameter is provided (given in the command) but is not defined (in the code), the method returns a errhelp error. Default CommandLine, which exits when parse is faulted (exitonerror)

For a deeper understanding, let's take a look at the source code for the parse (arguments []string):

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

}
The method of truly parsing parameters is non-export method Parseone.

In conjunction with the Parseone method, let us explain the sentence in Non-flag and pack documentation:

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

We need to understand when the parsing stops

According to the condition of the for loop termination in parse () (regardless of parsing error), we know that when Parseone returns false, nil, parse parsing terminates. We do not consider the normal parsing done. Look at the source of Parseone discovery, there are two places will return false, nil.

1) First Non-flag parameter

S: = F.args[0]
If Len (s) = = 0 | | S[0]! = '-' | | Len (s) = = 1 {
return false, Nil
}
That is, when you encounter a single "-" or not "-" start, it stops parsing. Like what:

./autogo–-f or./autogo build-f

In both cases,-f is not parsed correctly. Like the "-" or build (and later arguments) in this example, we call the Non-flag parameter

2) Two consecutive "–"

If s[1] = = '-' {
num_minuses++
If Len (s) = = 2 {//"--" terminates the flags
F.args = f.args[1:]
return false, Nil
}
}
That is, when a continuous two "-" is encountered, the parsing stops.

Description: This is the same as "-" and "–", Position and "-F". In other words, this is not the case here:

./autogo-f-

The "–" here will be treated as a value of F.

The next step in the Parseone method is to process the-flag=x, then the-flag (bool type) (where bool is treated specifically), followed by-flag X, and finally, the successful flag instance is stored in Flagset's actual map.

In addition, there is a sentence in Parseone:

1 F.args = f.args[1:]
That is, each execution succeeds once Parseone,f.args will be one less. So, the last thing that args in flagset to leave is all the non-flag parameters.

4, ARG (i int) and args (), Narg (), Nflag ()
The two methods of ARG (i int) and args () are to obtain the Non-flag parameter; Narg () obtains the number of Non-flag, and Nflag () obtains flagset length in actual (that is, the number of arguments set).

5, Visit/visitall
The two functions are used to access flag in Flatset's actual and formal, and the specific access method is determined by the caller.

6, Printdefaults ()
Print default values for all defined parameters (call Visitall), output to standard error by default, unless Flagset output (via Setoutput () setting) is specified

7, Set (name, value string)
Set the value of a flag (by name of flag)

V. Summary
Usage advice: Although it says so much, in general, we simply define flag and parse, just like the example of the beginning.

If your project requires complex or more advanced command-line parsing, you can try the Goptions package

If you want to handle multiple commands (subcommands) Like the Go tool, you can try command

Update:

2017-10-14: Complex command parsing, recommended HTTPS://GITHUB.COM/URFAVE/CLI or Https://github.com/spf13/cobra

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.