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: flag
conveniente análisis de línea de comandos.
Nota: Varios Distinción Concepción
- argumentos de línea de comandos (o parámetros): se refiere a los parámetros proporcionados para ejecutar el programa
- 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
- 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 flag
logramos 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 Xxx
puede 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 receiver
puntero), 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 languages
obtiene 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 -flag
esta forma, si el tipo bool no soporta -flag
esta 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/BoolVar
el 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.conf
el 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 CommandLine
de 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 -help
parámetro (comando dado), pero no definido (sin código), el método devuelve ErrHelp
un 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 parseOne
método, explicamos non-flag
y 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, nil
tiempo, 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, -c
no será resuelto correctamente. Como en este ejemplo, "-" o acumulación (y los parámetros posteriores), que llamamos non-flag
pará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 c
valor
parseOne el siguiente es un método de procesamiento -flag=x
en esta forma, a continuación, -flag
esta forma (tipo bool) (bool en el presente documento se ha diseñado especialmente para), entonces -flag x
esta 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-flag
parámetros.
Arg (i int) 和 Args (), narg (), nFlag ()
Arg (i int) y los Args () estos dos métodos es obtener el non-flag
parámetro; narG () obtenido non-flag
nú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.