golang 命令行
There are many ways to process CLI flags using Go. The first option is to not use any library at all, and inspect os.Args
. The second option is to use the standard library flag
package. The third option is to use one of the many 3rd party CLI libs out there, like Cobra.
有很多使用Go处理CLI标志的方法。 第一种选择是根本不使用任何库,并检查os.Args
。 第二种选择是使用标准库flag
包。 第三种选择是使用许多第三方CLI库之一,例如Cobra 。
Let’s talk about the second option: using the standard library flag
, as it offers many benefits over raw parsing of os.Args
and it’s built-in.
让我们来谈谈第二种选择:使用标准库flag
,因为它比os.Args
及其内置的原始解析提供了很多好处。
Add import "flag"
to the import section of your package, and it’s ready to use.
将import "flag"
添加到包的导入部分,即可使用。
To accept an int
parameter type:
要接受一个int
参数类型:
func Int(name string, value int, usage string) *int
var count = flag.Int("count", 5, "the count of items")
fmt.Println("count value ", *count)
The first parameter is the flag name as used in the CLI command, the second parameter is the default value, and the third is the description.
第一个参数是CLI命令中使用的标志名称,第二个参数是默认值,第三个参数是描述。
An alternative syntax is provided by flag.IntVar()
:
flag.IntVar()
提供了另一种语法:
func IntVar(p *int, name string, value int, usage string)
var count int
flag.IntVar(&count, "count", 5, "the count of items")
fmt.Println("count value ", count)
Here the parameters are shifted, and the first parameter is the variable reference.
在此,参数被移位,并且第一个参数是变量参考。
The main difference is that in the first case, you get a pointer. In the second case, you get a value.
主要区别在于,在第一种情况下,您将获得一个指针。 在第二种情况下,您可以获得价值。
flag
provides many functions to parse different flag types, you’ll need to use a different one for each type you want to accept:
flag
提供了许多函数来解析不同的标志类型,您需要为要接受的每种类型使用不同的标志:
func Bool(name string, value bool, usage string) *bool
func BoolVar(p *bool, name string, value bool, usage string)
func Duration(name string, value time.Duration, usage string) *time.Duration
func DurationVar(p *time.Duration, name string, value time.Duration, usage string)
func Float64(name string, value float64, usage string) *float64
func Float64Var(p *float64, name string, value float64, usage string)
func Int(name string, value int, usage string) *int
func Int64(name string, value int64, usage string) *int64
func Int64Var(p *int64, name string, value int64, usage string)
func IntVar(p *int, name string, value int, usage string)
func String(name string, value string, usage string) *string
func StringVar(p *string, name string, value string, usage string)
func Uint(name string, value uint, usage string) *uint
func Uint64(name string, value uint64, usage string) *uint64
func Uint64Var(p *uint64, name string, value uint64, usage string)
func UintVar(p *uint, name string, value uint, usage string)
Passing the wrong type for a flag will raise an error, halt the program, and the required usage will be printed to the user.
为标志传递错误的类型将引发错误,暂停程序,并且所需的用法将被打印给用户。
As an example, here’s how you parse a string:
例如,以下是解析字符串的方法:
var description = flag.String("description", "default value", "the description of the flag")
标志语法 (Flags syntax)
How do you set flag? Simple: attach -flagname
to your CLI command, with 4 alternative but equivalent syntaxes:
你如何设置标志? 简单:将-flagname
附加到CLI命令,并使用4种替代但等效的语法:
-count=x
-count x
--count=x
--count x
You can pass as many flags as you want to a command, but the first time flag
does not recognize a flag, it will stop parsing the additional ones. This means that flags must all go at the beginning, if you have non-flag parameters as well.
您可以根据需要向命令传递任意数量的标志,但是第一次flag
不能识别标志时,它将停止解析其他标志。 这意味着,如果您还具有非标志参数,则标志必须全部放在开头。
解析标志 (Parse the flags)
After defining all your flags, you need to call
定义所有标志后,您需要调用
flag.Parse()
to actually parse them.
实际解析它们。
布尔标志 (Boolean flags)
Boolean flags can be set just by adding -count
, which makes the boolean flag get the true
value. To set a false
value, use -count=false
. Any of those values are valid for boolean flags: 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
.
可以仅通过添加-count
来设置布尔标志,这会使布尔标志获得true
值。 要设置一个false
值,请使用-count=false
。 这些值中的任何一个对于布尔标志均有效: 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
。
简短的选择 (Short alternative)
Many times in the real world you’ll see CLI apps accepting a flag with a descriptive name, and the same flag with a letter abbreviation. You can do it by providing 2 flag handlers:
在现实世界中,很多时候您会看到CLI应用程序接受带有描述性名称的标志以及带有字母缩写的同一标志。 您可以通过提供2个标志处理程序来做到这一点:
var gopherType string
func init() {
const (
defaultGopher = "pocket"
usage = "the variety of gopher"
)
flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
}
解析非标志参数 (Parsing non-flag parameters)
The flag
package provides methods to also parse non-flag parameters.
flag
包提供了也可以解析非标志参数的方法。
flag.Args()
returns a slice of strings with the parameters not parsed as flags.
返回参数不解析为标志的字符串切片。
根据需要强制标记 (Forcing a flag as required)
The flag
package does not provide a built-in solution for this problem. You need to manage this case yourself:
flag
包不提供针对此问题的内置解决方案。 您需要自己处理这种情况:
// [...]
flag.Parse()
if *count == "" {
flag.PrintDefaults()
os.Exit(1)
}
更高级的主题 (More advanced topics)
This is an introductory article. You can go into more in-depth topics from here, like implementing subcommands and definining your own flag types. See https://blog.komand.com/build-a-simple-cli-tool-with-golang for more advanced usage of the CLI.
这是一篇介绍性文章。 您可以从这里进入更深入的主题,例如实现子命令和定义自己的标志类型。 有关CLI的更高级用法,请参见https://blog.komand.com/build-a-simple-cli-tool-with-golang 。
参考 (Reference)
https://thenewstack.io/cli-command-line-programming-with-go/
https://thenewstack.io/cli-command-line-programming-with-go/
golang 命令行