Este artigo Endereço original: https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/edit/master/chapter13/13.1.md
enquanto o programa de linha de comando escrita (ferramentas, servidores), parâmetros de comando análise é uma exigência comum. Várias línguas costumam fornecer um método para analisar parâmetros de linha de comando ou biblioteca para facilitar os programadores a usar. Se os argumentos de linha de comando puramente para escrever a sua própria análise de código para mais complexa, ou muito extenuante. Fornecidas no go biblioteca padrão em um pacote: flag
conveniente de análise de linha de comando.
Nota: Vários Distinção Conceição
- argumentos de linha de comando (ou parâmetros): refere-se aos parâmetros fornecidos para executar o programa
- linha de comando parâmetros foram definidos: refere-se ao processo definido pelos parâmetros deste forma como flag.Xxx
- Non bandeira (non-flag) argumentos de linha de comando (parâmetros de linha de comando ou retidos): explicado mais tarde
Exemplos de Utilização
Nós nginx por exemplo, a implementação de nginx -h, a saída é a seguinte:
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
Nós flag
alcançar nginx semelhante esta saída, crie um arquivo nginx.go, tem o seguinte teor:
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()
}
Realizada: Vai correr nginx.go -H, (ou ir construção -o nginx && ./nginx -h) de saída é a seguinte:
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
Cuidadosamente apreciado que o exemplo acima, se não é entendido, depois de ler o seguinte Volte explicação e olhar.
flag saco Overview
flag
implementos pacote parsing parâmetros de linha de comando.
Há duas maneiras de definir bandeiras
1) flag.Xxx (), que Xxx
pode ser Int, String semelhantes; retorna um ponteiro para o tipo apropriado, tais como:
var ip = flag.Int("flagname", 1234, "help message for flagname")
2) flag.XxxVar (), a bandeira ligado a uma variável, tais como:
var flagvar int
flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
Valor personalizado
Além disso, você pode criar uma bandeira personalizada, desde que a interface pode ser implementada flag.Value (reivindicação receiver
ponteiro), a bandeira neste momento pode ser definido por:
flag.Var(&flagVal, "name", "help message for flagname")
Por exemplo, a minha análise favorito linguagem de programação, esperamos resolver diretamente à fatia, podemos definir o seguinte valor:
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), ",") }
Depois de usar:
var languages []string
flag.Var(newSliceValue([]string{}, &languages), "slice", "I like programming `languages`")
Por assim -slice "go,php"
passando os parâmetros de tal forma uma languages
obtido é [go, php]
.
Duração desta bandeira do tipo não-básico de suporte utilizada é semelhante desta forma.
bandeira análise
Afinal a bandeira definido, chamando flag.Parse()
para a resolução.
A sintaxe da bandeira linha de comando pode assumir três formas:
-flag // 只支持 bool 类型
-flag=x
-flag x // 只支持非 bool 类型
A terceira forma que só pode ser usado para o tipo não-bool de bandeira, a razão é: Se isso acontecer, então para este comando cmd -x *, se não houver um nome de arquivo é: 0 ou a mudança falsa vontade intenção e assim por diante, o comando do ( a razão para isso é porque o tipo bool apoio -flag
esta forma, se o tipo bool não suporta -flag
esta forma, você pode digitar bool e outros tipos de um mesmo processo. é por isso, Parse (), o tipo de bool para um tratamento especial) . Padrão é fornecido -flag
, o valor correspondente é verdadeiro, caso contrário, flag.Bool/BoolVar
o valor padrão especificado; se você quiser exibição é definido como uso falsa -flag=false
.
Tipo int pode ser decimal, hexadecimal, octal, ou mesmo negativo, tipo bool pode ser 1, 0, t, f, verdadeiro, falso, TRUE, FALSE, True, False. Duração pode aceitar qualquer tipo de time.ParseDuration pode ser resolvido.
Tipos e funções
Antes de olhar para os tipos e funções, olhar para as variáveis.
ErrHelp: O tipo errado é usado quando os parâmetros de linha de comando especificado quando · -help` mas não definido.
Uso: Esta é uma função que define a saída de todos os argumentos de linha de comando e informações de ajuda (mensagem de uso). Em geral, quando um erro ao analisar parâmetros de linha de comando, a função é chamada. Podemos especificar sua própria função de Uso, a saber:flag.Usage = func(){}
função
ir biblioteca padrão, muitas vezes fazer:
Definição de um tipo, um número de maneiras; por conveniência, irá criar uma instância (genérico) deste tipo, para que ele possa usar diretamente o método de instância chamada. Por exemplo: de codificação / base 64 e fornece exemplo StdEncoding URLEncoding, uso: base64.StdEncoding.Encode ()
Bandeira no pacote utilizando modos similares, como exemplos CommandLine, mas foram adicionalmente encapsulado bandeira: a métodos redefinir FlagSet novamente, isto é, proporciona uma sequência de funções, e função simplesmente chamada instanciado o exemplo bom FlagSet: método de linha de comando. Desta forma, o usuário é tão chamada :. Flag.Parse () em vez de CommandLine.Parse bandeira (). (Ir 1.2 a partir da exportação de linha de comando, não previamente exportados)
Cada função não é descrita aqui em detalhe, do tipo descrito no processo.
Tipos (estruturas de dados)
1) ErrorHandling
type ErrorHandling int
Este tipo define a manipulação de erro quando o parâmetro de erro modo de análise. Isto define três tipos de constantes:
const (
ContinueOnError ErrorHandling = iota
ExitOnError
PanicOnError
)
Três constantes utilizadas no método fonte parseOne FlagSet () de.
2) Bandeira
// 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 de bandeira representa um estado bandeira.
Por exemplo, para o comando: ./nginx -c /etc/nginx.conf
o código correspondente é:
flag.StringVar(&c, "c", "conf/nginx.conf", "set configuration `file`")
Exemplos da bandeira (pode flag.Lookup("c")
ser obtido) correspondente para o 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) Interface de 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 Valor implementar todas as interfaces necessárias, pacote de bandeira, como int, float, bool outros implementa a interface. Com esta interface, podemos personalizar a bandeira. (Exemplos específicos acima foram dadas)
Os principais tipos de processos (incluindo tipo instanciação)
flag é principalmente FlagSet tipo de pacote.
Exemplos da maneira
NewFlagSet()
Exemplos de FlagSet. Exemplos de pré-definido FlagSet CommandLine
maneira definida:
// The default set of command-line flags, parsed from os.Args.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
Visível, o padrão FlagSet instância ao analisar erro irá sair do programa.
Uma vez que o campo não é em FlagSet exportação, FlagSet Exemplo obtida de outro modo, tais como: FlagSet {} ou nova (FlagSet), ele deve ser chamado método Init (), e para inicializar nome ErrorHandling, ou o nome está vazia, como ErrorHandling ContinueOnError.
O método definido bandeira parâmetro
Este método sequcia tem duas formas, no início foi dito a diferença entre as duas abordagens. Estes métodos são utilizados para definir os parâmetros de um determinado tipo de bandeira.
Os parâmetros analíticos (Analisar)
func (f *FlagSet) Parse(arguments []string) error
Analisando bandeira definida na lista de parâmetros. O método não inclui um nome de comando argumentos de parâmetros, ou seja, deve ser os.Args [1:]. Na verdade, flag.Parse()
a função fez exatamente isso:
// 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:])
}
O método deve ser o valor do parâmetro específico do parâmetro após a bandeira foi chamadas de acesso previamente definido.
Se um -help
parâmetro (ordem dada), mas não definido (sem código), o método retorna ErrHelp
um erro. A linha de comando padrão, quando erro Parse vai sair do programa (ExitOnError).
Para uma melhor compreensão, olhamos para o Parse(arguments []string)
código-fonte:
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
}
Não verdadeiro método de método de resolução de parâmetros derivação parseOne
.
Combinada parseOne
método, vamos explicar non-flag
e saco de documentos nesta frase:
Bandeira de análise pára pouco antes de o primeiro argumento não-bandeira ( "-" é um argumento não-flag) ou depois do terminator "-".
Precisamos saber quando parar de análise.
De acordo com Parse () condições de loop para a rescisão (sem levar em conta erros analíticos), sabemos que quando parseOne retorno false, nil
tempo, Parse analisar encerrado. Nós não consideramos a conclusão normal da análise. ParseOne olhada no código fonte descobriram que os dois retornos false, nil
.
1) um primeiro parâmetro de não-bandeira
s := f.args[0]
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
return false, nil
}
Isto é, quando confrontados com uma separado "-" ou não "-" no início, parada de resolver. Por exemplo:
./nginx - -c 或 ./nginx -c construção
Em ambos os casos, -c
ele não vai ser resolvido corretamente. Como neste exemplo, "-" ou de construção (e os parâmetros subsequentes), chamamos non-flag
parâmetros.
2) dois sucessivos "-"
if s[1] == '-' {
num_minuses++
if len(s) == 2 { // "--" terminates the flags
f.args = f.args[1:]
return false, nil
}
}
Isto é, quando confrontado com dois consecutivos "-", a análise pára.
Descrição: que é "-" e "-" posição e "c" Este é o mesmo. Em outras palavras, o seguinte cenário não está aqui para dizer:
./nginx -c -
Aqui, "-" será tratada como um c
valor
parseOne o seguinte é um método de processamento -flag=x
nesta forma, em seguida, -flag
esta forma (tipo booleano) (boleano aqui foi especialmente concebido para), em seguida -flag x
esta forma, finalmente, os exemplos de sucesso Parses bandeira mapa real armazenado no FlagSet no.
Além disso, em parseOne em tal sentença a:
f.args = f.args[1:]
Ou seja, cada executado com sucesso uma vez parseOne, f.args um a menos. Então, FlagSet os argumentos última estadia é que todos os non-flag
parâmetros.
Arg (i int) 和 Args (), nArg (), nFlag ()
Arg (i int) e os Args () destes dois métodos é a obtenção do non-flag
parâmetro; nArg () obtido non-flag
número; (isto é, o número de conjuntos de parâmetros) nFlag () para obter o comprimento real FlagSet.
Visita / VisitAll
Estas duas funções são usadas para acesso a FlatSet real e formal da Bandeira, e método de acesso específico é determinado pelo chamador.
PrintDefaults ()
Imprimir todos os padrões parâmetros definidos (chamada VisitAll conseguir), a saída padrão para o erro padrão, a menos que a saída FlagSet designado (por SetOutput () definição)
Definir (nome, cadeia de valor)
Definir um valor bandeira (bandeira por encontrar o nome correspondente)
resumo
Sugestão de uso: Embora o acima falou sobre muito, em geral, nós simplesmente definir bandeira, e, em seguida, analisar, apenas como um exemplo do início da mesma.
Se o seu projeto requer mais modo de análise de linha de comando avançado ou complexo, você pode usar https://github.com/urfave/cli ou https://github.com/spf13/cobra estes dois poderosa biblioteca.