英文:
Is a bug: flag.Parse() could not get values after bool arg?
问题
为什么无法在命令行中获取以下布尔类型参数的值?以下是我的测试代码:
import (
"flag"
"fmt"
)
var stringVal string
var intVal int
var boolValue bool
func init() {
flag.StringVar(&stringVal, "s", "", "string value")
flag.BoolVar(&boolValue, "b", false, "bool value")
flag.IntVar(&intVal, "i", -1, "int value")
}
func main() {
flag.Parse()
fmt.Println("stringVal:", stringVal, ", boolValue:", boolValue, ", intVal:", intVal)
}
运行方式:
go run flag.go -s test -b true -i 10
得到结果:stringVal: test , boolValue: true , intVal: -1go run flag.go -s test -b false -i 10
得到结果:stringVal: test , boolValue: true , intVal: -1go run flag.go -b false -s test -i 10
得到结果:stringVal: , boolValue: true , intVal: -1go run flag.go -s test -i 10 -b false
得到结果:stringVal: test , boolValue: true , intVal: 10
Go 版本:1.16
英文:
Why could not get the values that following bool type arg in the command line?
Here's my test code:
import (
"flag"
"fmt"
)
var stringVal string
var intVal int
var boolValue bool
func init() {
flag.StringVar(&stringVal, "s", "", "string value")
flag.BoolVar(&boolValue, "b", false, "bool value")
flag.IntVar(&intVal, "i", -1, "int value")
}
func main() {
flag.Parse()
fmt.Println("stringVal:", stringVal, ", boolValue:", boolValue, ", intVal:", intVal)
}
Run it as:
go run flag.go -s test -b true -i 10
Got: stringVal: test , boolValue: true , intVal: -1go run flag.go -s test -b false -i 10
Got: stringVal: test , boolValue: true , intVal: -1go run flag.go -b false -s test -i 10
Got: stringVal: , boolValue: true , intVal: -1go run flag.go -s test -i 10 -b false
Got: stringVal: test , boolValue: true , intVal: 10
Go version: 1.16
答案1
得分: 6
布尔标志是根据标志的存在与否来设置的。它们通常默认为false,并且标志的存在用于修改默认行为。
例如...
- 要显示目录的长格式列表,你使用的是
ls -l
,而不是ls -l true
- 要通过交互式提示使
rm
更安全,以便询问是否删除,你使用的是rm -i
,而不是rm -i true
- 要使用
df
显示可读的输出,你使用的是df -h
,而不是df -h true
你在-b
之后放置的true
和false
被作为参数提供给你的程序,而不是作为标志,它们的存在会中断后续的标志处理。
在你的main
函数末尾添加以下内容:
fmt.Println("Remaining args", flag.Args())
假设你这样调用:go run flag.go -b false -s test -i 10
,你会看到标志处理停在了false
,剩余的参数作为非标志参数传递给你的程序:
$ go run flag.go -b false -s test -i 10
stringVal: , boolValue: true , intVal: -1
Remaining args [false -s test -i 10]
顺便说一下,“布尔”标志背后的一般理念是给你的程序一些默认行为,并提供两个标志:一个修改默认行为,另一个相反的标志来取消修改,恢复默认行为。在处理标志时,最后一个标志会覆盖之前的标志。
例如,rm
提供了-i
来使命令交互式,并提供了-f
来取消-i
标志。
这样,你可以在shell中设置alias rm="rm -i"
,这意味着所有的rm
调用都会应用-i
标志以确保安全,在删除文件之前会提示你。然而,如果你想运行一个非交互式的rm
,你仍然可以输入rm -f
,它会扩展为rm -i -f
,最后一个标志(-f
)会生效。否则,你每次想要非交互式调用时都需要取消别名,运行rm
,然后恢复别名。
英文:
Boolean flags are set based on the presence or absence of the flag. They typically default to false, and the presence of the flag is used to modify the default behavior.
For example...
- to display the long listing of a directory with
ls
, you usels -l
, notls -l true
- to make
rm
safer by having it interactively prompt for deletes, you userm -i
, notrm -i true
- to display human-readable output with
df
, you usedf -h
, notdf -h true
The true
and false
you're placing after the -b
are being provided to your program as arguments, not as flags, and their presence interrupts further processing of flags.
Add the following to the end of your main
function:
fmt.Println("Remaining args", flag.Args())
Given an invocation such as go run flag.go -b false -s test -i 10
, you'll see that flag processing stopped at false
, and that the remaining arguments are passed to your program as non-flag arguments:
$ go run flag.go -b false -s test -i 10
stringVal: , boolValue: true , intVal: -1
Remaining args [false -s test -i 10]
As an aside, the general philosophy behind "boolean" flags is that you give your program some default behavior, and provide two flags: One which modifies that default, and an opposite flag that negates the modification, restoring the default. When processing flags, the last flag will win.
For example, rm
provides -i
to make the command interactive, and -f
to negate the -i
flag.
This allows you to set alias rm="rm -i"
in your shell, meaning all invocations of rm
will have the -i
flag applied for safety, prompting you before removing files. However, if you want to run a non-interactive rm
, you can still type rm -f
, which expands to be rm -i -f
, and the last flag (-f
) wins. Otherwise, you'd have destroy the alias, run rm
and then restore the alias every time you wanted a non-interactive invocation.
答案2
得分: 3
一个布尔标志测试的是标志的存在,而不是它的值。如果你想设置一个值,请使用:
go run flag.go -s test -b=false -i 10
英文:
A boolean flag tests the existence of the flag, not the value of it. If you want to set a value, use:
go run flag.go -s test -b=false -i 10
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论