在 Cobra 命令行工具中,如何为不同的标志使用相同的变量?
In Cobra command-line tool, how to use the same variable for different flags?
此示例 Cobra 应用程序 https://github.com/kurtpeek/myCobraApp 包含一个使用 Cobra 生成器和以下命令构建的 Cobra 应用程序脚手架:
cobra add serve
cobra add config
目录结构为
.
├── LICENSE
├── cmd
│ ├── config.go
│ ├── root.go
│ └── serve.go
├── go.mod
├── go.sum
└── main.go
在 config.go
中,字符串变量 deviceUUID
被定义并绑定到该命令的标志,默认值为 "configDeviceUUID"
:
var deviceUUID string
func init() {
rootCmd.AddCommand(configCmd)
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
fmt.Println("deviceUUID after config init:", deviceUUID)
}
类似地,在 serve.go
中,deviceUUID
变量绑定到本地标志:
func init() {
rootCmd.AddCommand(serveCmd)
serveCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "serveDeviceUUID", "Device UUID")
fmt.Println("deviceUUID after serve init:", deviceUUID)
}
问题是,如果我 运行 config
命令没有在命令行指定 deviceUUID
标志,它会从 serve
命令:
> go run main.go config
deviceUUID after config init: configDeviceUUID
deviceUUID after serve init: serveDeviceUUID
deviceUUID: serveDeviceUUID
config called
似乎正在发生的事情是每个文件中的 init()
函数按字母顺序排列 运行,最后一个 运行 设置标志的默认值。
如何避免这种行为?我希望 config.go
中设置的默认值始终应用于 config
命令。 (当然,我可以声明单独的变量,如 configDeviceUUID
和 serveDeviceUUID
,但这对我来说似乎有点混乱)。
我不知道为什么你会认为凌乱。你有一个变量,你在几个 init
函数中设置了它,所以 last 设置是保持设置的那个:你对正在发生的事情的解释是正确的。显然,这实际上是两个不同的变量,只是其中最多一个会被 used.
(假设还有其他命令做其他事情,也许 none 这些全局变量将被使用。如果 Go 是一种自然更动态的语言其中 一切 都是在运行时决定的,或者如果您使用的是更动态的运行时设置,您可以创建其中的 none 。但这不是 Go:Go 是充满静态类型和静态变量,创建于 link 时间。)
如果你真的只想使用一个全局变量,那么显而易见的解决方案是选择一些标记值来表示未设置,并将其设为默认值眼镜蛇套装。然后,如果变量在 运行 命令中保持 "not set" 值,则您知道用户没有提供值。
如果空字符串适合作为标记——通常是这种情况——这很容易。您的每个命令都会增加几行:
if deviceUUID == "" {
deviceUUID = defaultDeviceUUID
}
大功告成。
如果 cobra 代码将默认初始化程序值保存在某处 private,这可能会更好,或者至少对您来说更方便:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
然后将那些私有的、保存的默认值复制到(单个)全局变量中当顶级命令决定使用config
子命令时,而不是不将它保存在私有的某个地方,并在调用 configCmd.Flags().StringVar()
函数时将其复制到 中的(单个)全局变量中 ,但事实并非如此确实有效。所以:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "", "Device UUID")
加上上面的空字符串测试可能就足够了。请注意,每个 init
仍然每次都覆盖(单个,共享,甚至可能从未使用过)全局变量,但它们都将其从初始空字符串值设置为新的空字符串 -字符串值,保持不变。
此示例 Cobra 应用程序 https://github.com/kurtpeek/myCobraApp 包含一个使用 Cobra 生成器和以下命令构建的 Cobra 应用程序脚手架:
cobra add serve
cobra add config
目录结构为
.
├── LICENSE
├── cmd
│ ├── config.go
│ ├── root.go
│ └── serve.go
├── go.mod
├── go.sum
└── main.go
在 config.go
中,字符串变量 deviceUUID
被定义并绑定到该命令的标志,默认值为 "configDeviceUUID"
:
var deviceUUID string
func init() {
rootCmd.AddCommand(configCmd)
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
fmt.Println("deviceUUID after config init:", deviceUUID)
}
类似地,在 serve.go
中,deviceUUID
变量绑定到本地标志:
func init() {
rootCmd.AddCommand(serveCmd)
serveCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "serveDeviceUUID", "Device UUID")
fmt.Println("deviceUUID after serve init:", deviceUUID)
}
问题是,如果我 运行 config
命令没有在命令行指定 deviceUUID
标志,它会从 serve
命令:
> go run main.go config
deviceUUID after config init: configDeviceUUID
deviceUUID after serve init: serveDeviceUUID
deviceUUID: serveDeviceUUID
config called
似乎正在发生的事情是每个文件中的 init()
函数按字母顺序排列 运行,最后一个 运行 设置标志的默认值。
如何避免这种行为?我希望 config.go
中设置的默认值始终应用于 config
命令。 (当然,我可以声明单独的变量,如 configDeviceUUID
和 serveDeviceUUID
,但这对我来说似乎有点混乱)。
我不知道为什么你会认为凌乱。你有一个变量,你在几个 init
函数中设置了它,所以 last 设置是保持设置的那个:你对正在发生的事情的解释是正确的。显然,这实际上是两个不同的变量,只是其中最多一个会被 used.
(假设还有其他命令做其他事情,也许 none 这些全局变量将被使用。如果 Go 是一种自然更动态的语言其中 一切 都是在运行时决定的,或者如果您使用的是更动态的运行时设置,您可以创建其中的 none 。但这不是 Go:Go 是充满静态类型和静态变量,创建于 link 时间。)
如果你真的只想使用一个全局变量,那么显而易见的解决方案是选择一些标记值来表示未设置,并将其设为默认值眼镜蛇套装。然后,如果变量在 运行 命令中保持 "not set" 值,则您知道用户没有提供值。
如果空字符串适合作为标记——通常是这种情况——这很容易。您的每个命令都会增加几行:
if deviceUUID == "" {
deviceUUID = defaultDeviceUUID
}
大功告成。
如果 cobra 代码将默认初始化程序值保存在某处 private,这可能会更好,或者至少对您来说更方便:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "configDeviceUUID", "Device UUID")
然后将那些私有的、保存的默认值复制到(单个)全局变量中当顶级命令决定使用config
子命令时,而不是不将它保存在私有的某个地方,并在调用 configCmd.Flags().StringVar()
函数时将其复制到 中的(单个)全局变量中 ,但事实并非如此确实有效。所以:
configCmd.Flags().StringVar(&deviceUUID, "deviceUUID", "", "Device UUID")
加上上面的空字符串测试可能就足够了。请注意,每个 init
仍然每次都覆盖(单个,共享,甚至可能从未使用过)全局变量,但它们都将其从初始空字符串值设置为新的空字符串 -字符串值,保持不变。