Ir en paquetes de la bandera.

Este artículo original Dirección: https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/edit/master/chapter13/13.1.md
mientras que el programa de línea de comandos de escritura (herramientas, servidores), parámetros de comando análisis sintáctico es una demanda común. Varios idiomas por lo general proporcionan un método para analizar los parámetros de la línea de comandos o la biblioteca para facilitar los programadores utilizar. Si los argumentos de línea de comandos puramente a escribir su propio código para el análisis más complejo, o muy extenuante. Proporcionada en la marcha de la biblioteca estándar en un paquete: flagconveniente análisis de línea de comandos.

Nota: Varios Distinción Concepción

  1. argumentos de línea de comandos (o parámetros): se refiere a los parámetros proporcionados para ejecutar el programa
  2. Se han definido los parámetros de línea de comando: se refiere al procedimiento definido por los parámetros de esta forma como flag.Xxx
  3. Non bandera (no-flag) argumentos de línea de comandos (parámetros de línea de comando o retenido): explica más adelante

Ejemplos de Uso

Nos Nginx por ejemplo, la implementación de nginx -h, la salida es la siguiente:

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

Nosotros flaglogramos nginx similares esta salida, creamos un archivo nginx.go, dice lo siguiente:

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()
}

Realizado: Go ejecutar nginx.go -H, (o ir de construcción -o nginx && ./nginx -h) salida es la siguiente:

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

Con cuidado apreciarse que el ejemplo anterior, si no se entiende, después de leer la siguiente vuelta ir explicación y aspecto.

Descripción general de la bandera bolsa

flag implementos del paquete de análisis sintáctico parámetros de línea de comandos.

Hay dos maneras de definir las banderas

1) flag.Xxx (), que Xxxpuede ser int, String similares; devuelve un puntero al tipo adecuado, tales como:

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

2) flag.XxxVar (), la bandera unido a una variable, tales como:

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

Valor

Además, puede crear una marca personalizada, siempre que la interfaz puede ser implementada flag.Value (reivindicación receiverpuntero), la bandera en este momento puede ser definido por:

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

Por ejemplo, mi análisis sintáctico del lenguaje de programación favorito, esperamos resolver directamente a la división, podemos definir el valor siguiente:

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

Después de tanto usar:

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

Por lo -slice "go,php"pasando los parámetros en forma de un tal languagesobtiene es [go, php].

Duración de esta bandera en el tipo no básico del soporte utilizado es similar en este camino.

bandera de análisis sintáctico

Después de todo la bandera definido, llamando flag.Parse()para su resolución.

La sintaxis de la bandera de línea de comandos puede tomar tres formas:

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

La tercera forma que sólo puede ser utilizado para el tipo no-bool de la bandera, la razón es la siguiente: Si lo hace, entonces para este comando cmd-x *, si hay un nombre de archivo es: 0 o falso cambio de voluntad intención y así sucesivamente, el mando de la ( la razón de esto es porque el apoyo de tipo bool -flagesta forma, si el tipo bool no soporta -flagesta forma, puede escribir bool y otros tipos de un mismo proceso. es debido a esto, Parse (), el tipo de bool para un tratamiento especial) . Por defecto se proporciona -flag, el valor correspondiente es cierto, de lo contrario flag.Bool/BoolVarel valor predeterminado especificado, si desea mostrar está configurado para utilizar falsa -flag=false.

tipo int puede ser decimal, hexadecimal, octal, o incluso negativo; tipo bool puede ser 1, 0, t, f, verdadero, falso, VERDADERO, FALSO, True, False. La duración puede aceptar cualquier tipo de time.ParseDuration se puede resolver.

Tipos y funciones

Antes de examinar los tipos y funciones, mirar las variables.

ErrHelp: El tipo incorrecto se utiliza cuando los parámetros de línea de comando especificado cuando · -help` pero no definidos.

Uso: Se trata de una función que define la salida de todos los argumentos de línea de comandos e información de ayuda (mensaje de uso). En general, cuando un error al analizar los parámetros de línea de comandos, se invoca la función. Podemos especificar su propia función de uso, a saber:flag.Usage = func(){}

función

ir a la biblioteca estándar, a menudo hacer:

Definición de un tipo, un número de maneras, por conveniencia, se crear una instancia (genérico) de este tipo, de modo que pueda utilizar directamente el método de instancia llamada. Por ejemplo: la codificación / base64 y proporciona instancia StdEncoding URLEncoding, uso: base64.StdEncoding.Encode ()

Flag en el paquete utilizando métodos similares, como ejemplos CommandLine, pero fueron encapsulados además bandera: a métodos Redefinir Flagset de nuevo, es decir, proporciona una secuencia de funciones, y la función simplemente llamada instanciada el ejemplo buena Flagset: método CommandLine. De esta manera, el usuario es tan llamada :. Flag.Parse () en lugar de CommandLine.Parse indicador (). (Go 1.2 de la exportación CommandLine, no previamente exportada)

Cada función no se describe en detalle en este documento, del tipo descrito en el proceso.

Los tipos (estructuras de datos)

1) ErrorHandling

type ErrorHandling int

Este tipo define el manejo de errores cuando el parámetro de error modo de análisis sintáctico. Esto define tres tipos de constantes:

const (
	ContinueOnError ErrorHandling = iota
	ExitOnError
	PanicOnError
)

Tres constantes utilizadas en el método fuente parseOne Flagset () de.

2) Bandera

// 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
}

tipo bandera representa un estado de la bandera.

Por ejemplo, para el comando: ./nginx -c /etc/nginx.confel código correspondiente es:

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

Ejemplos de la bandera (puede flag.Lookup("c")ser obtenido) correspondiente al valor de cada campo:

&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) Interfaz Valor

// 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
}

Parámetro Tipo Valor implementar todas las interfaces necesarias, el paquete de bandera, como int, float, bool otros implementos de la interfaz. Con esta interfaz, se puede personalizar la bandera. (Ejemplos específicos anteriores se han dado)

Los principales tipos de procesos (incluyendo el tipo de instancias)

bandera es principalmente Flagset tipo de paquete.

Los ejemplos de la forma

NewFlagSet()Ejemplos de Flagset. Ejemplos de Flagset predefinido CommandLinede forma definida:

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

Visible, el valor predeterminado Flagset ejemplo, al analizar el error será salir del programa.

Debido a que el campo no es en Flagset Export, Flagset Ejemplo obtenerse de otro modo, tales como: Flagset {} o nuevo (Flagset), que debería ser llamado método Init (), y para inicializar nombre ErrorHandling, o el nombre está vacío, como ErrorHandling ContinueOnError.

La bandera parámetro método definido

Este método de secuencia tiene dos formas, desde el principio, se ha dicho que la diferencia entre los dos enfoques. Estos métodos se utilizan para definir los parámetros de un cierto tipo de bandera.

parámetros analíticos (Parse)

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

Analizar bandera se define en la lista de parámetros. El método no incluye un parámetro de nombre de comando argumentos, es decir, debe ser os.Args [1:]. De hecho, flag.Parse()la función fue lo que hizo:

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

El método debe ser valor de parámetro específico del parámetro después de la bandera se definió anteriormente llamadas de acceso.

Si un -helpparámetro (comando dado), pero no definido (sin código), el método devuelve ErrHelpun error. La línea de comandos predeterminada, cuando Error de análisis se salga del programa (ExitOnError).

Para una mejor comprensión, nos fijamos en el Parse(arguments []string)código fuente:

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
}

No verdadero método de método de resolución de los parámetros de derivación parseOne.

Combinado parseOnemétodo, explicamos non-flagy la bolsa de documento en esta frase:

Bandera análisis finaliza justo antes del primer argumento que no es la bandera ( "-" es un argumento que no es la bandera) o después del terminador "-".

Tenemos que saber cuándo dejar de análisis.

De acuerdo con las condiciones de bucle Parse () para la terminación (sin tener en cuenta el error analítico), sabemos que cuando el retorno parseOne false, niltiempo, Parse análisis sintáctico terminado. No consideramos la finalización normal del análisis. ParseOne vistazo al código fuente encontró que los dos retornos false, nil.

1) un primer parámetro no bandera

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

Es decir, cuando se enfrentan a una por separado "-" o no "-" en el inicio, parada resolviendo. Por ejemplo:

./nginx - -c 或 ./nginx acumulación -c

En ambos casos, -cno será resuelto correctamente. Como en este ejemplo, "-" o acumulación (y los parámetros posteriores), que llamamos non-flagparámetros.

2) dos sucesivos "-"

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

Es decir, cuando se enfrentan a dos años consecutivos "-", el análisis se detiene.

Descripción: Es "-" y "-" posición y "c" Este es el mismo. En otras palabras, el siguiente escenario no está aquí para decir:

./nginx -c -

Aquí, "-" será tratado como un cvalor

parseOne el siguiente es un método de procesamiento -flag=xen esta forma, a continuación, -flagesta forma (tipo bool) (bool en el presente documento se ha diseñado especialmente para), entonces -flag xesta forma, por último, ejemplos de análisis sintácticos de éxito de la bandera de mapa real almacenan en la Flagset en.

Además, en parseOne en dicha frase a:

f.args = f.args[1:]

Es decir, cada vez que se ha ejecutado correctamente parseOne, f.args uno menos. Por lo tanto, los argumentos Flagset última estancia es que todos los non-flagparámetros.

Arg (i int) 和 Args (), narg (), nFlag ()

Arg (i int) y los Args () estos dos métodos es obtener el non-flagparámetro; narG () obtenido non-flagnúmero; (es decir, el número de conjuntos de parámetros) nFlag () para obtener la longitud real Flagset.

Visit / VisitAll

Estas dos funciones se utilizan para acceder a la FlatSet real y formal de la bandera, y el método de acceso específico está determinado por la persona que llama.

PrintDefaults ()

Imprimir todos los valores predeterminados parámetros definidos (llamada VisitAll lograr), la salida predeterminada de error estándar, a menos que Flagset designa la salida (por SetOutput (a) Explotación)

Set (nombre, cadena de valor)

El establecimiento de un valor de bandera (Bandera de los hallazgos el nombre correspondiente)

resumen

Uso sugerido: A pesar de lo anterior hablado tanto, en general, simplemente definimos bandera, y luego analizar sintácticamente, sólo como un ejemplo del comienzo de la misma.

Si su proyecto requiere el modo más avanzado o complejo de línea de comandos de análisis, puede utilizar https://github.com/urfave/cli  o  https://github.com/spf13/cobra estos dos biblioteca de gran alcance.

Supongo que te gusta

Origin www.cnblogs.com/MaxBaiSecurity/p/12651587.html
Recomendado
Clasificación