英文:
Using env variables in YML with default value
问题
我有以下代码来读取包含环境变量的yml配置文件:
confContent, err := ioutil.ReadFile("config.yml")
if err != nil {
panic(err)
}
// 扩展环境变量
confContent = []byte(os.ExpandEnv(string(confContent)))
conf := &SysConfig{}
if err := yaml.Unmarshal(confContent, conf); err != nil {
panic(err)
}
config.yml
db:
name: ${DB_NAME:qm}
host: localhost
它可以工作,但是如果没有提供DB_NAME
环境变量,我该如何让它读取默认值呢?
英文:
I have the following code to read config files from yml which includes ENV variables too:
confContent, err := ioutil.ReadFile("config.yml")
if err != nil {
panic(err)
}
// expand environment variables
confContent = []byte(os.ExpandEnv(string(confContent)))
conf := &SysConfig{}
if err := yaml.Unmarshal(confContent, conf); err != nil {
panic(err)
}
config.yml
db:
name: ${DB_NAME:qm}
host: localhost
It is working but how can I get it to read default values if DB_NAME
env is not given?
答案1
得分: 6
你可以使用Expand
函数替换ExpandEnv
中的映射器,并考虑默认值,代码如下:
package main
import (
"fmt"
"os"
"strings"
)
func main() {
mapper := func(placeholderName string) string {
split := strings.Split(placeholderName, ":")
defValue := ""
if len(split) == 2 {
placeholderName = split[0]
defValue = split[1]
}
val, ok := os.LookupEnv(placeholderName)
if !ok {
return defValue
}
return val
}
os.Setenv("DAY_PART", "morning")
fmt.Println(os.Expand("Good ${DAY_PART:test}, ${NAME:Gopher}", mapper))
}
这将输出:
Good morning, Gopher
这是根据os包文档中的Expand示例进行的修改。
英文:
You can replace the mapper on ExpandEnv
using Expand
and take into account default values like this:
package main
import (
"fmt"
"os"
"strings"
)
func main() {
mapper := func(placeholderName string) string {
split := strings.Split(placeholderName, ":")
defValue := ""
if len(split) == 2 {
placeholderName = split[0]
defValue = split[1]
}
val, ok := os.LookupEnv(placeholderName)
if !ok {
return defValue
}
return val
}
os.Setenv("DAY_PART", "morning")
fmt.Println(os.Expand("Good ${DAY_PART:test}, ${NAME:Gopher}", mapper))
}
this will render
Good morning, Gopher
This is based on the example from Expand from the os package documentation.
答案2
得分: 2
我建议你使用由spf13开发的强大的Viper包来读取配置文件,它可以优雅地解决你的问题,并且你可以使用它来加载其他类型的配置文件。
解决你的问题
- 获取该包
go get github.com/spf13/viper
- 配置文件
假设你有一个名为db.yaml
的配置文件:
db:
name: somedb
host: localhost
- 代码示例
正如我们所看到的,一旦Viper加载了配置文件,我们可以通过键获取值。Yaml文件将被解析为一个嵌套结构,你可以将其解组为Golang结构体。我们应该使用viper.GetString("db.name")
来获取值,你可以参考这个页面获取更多用法信息。
import (
"fmt"
"github.com/spf13/viper"
)
func InitConf() {
viper.AutomaticEnv() // 读取系统环境变量
viper.SetConfigName("db") // 要加载的配置文件名
viper.AddConfigPath(".") // 配置文件路径
viper.SetDefault("db.name", "mysqldb") // 在这里设置默认的数据库名称
// 读取配置文件并处理错误
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// 配置文件未找到;如果需要,可以忽略错误
} else {
// 配置文件找到,但产生了其他错误
}
}
fmt.Printf("db.name: %s", viper.GetString("db.name"))
}
viper.AutomaticEnv()
方法将自动读取系统环境变量,假设你有一个名为ENV_XXX
的环境变量,那么你可以通过viper.GetString("ENV_XXX")
获取它。如果环境变量的名称与配置文件的键相同,Viper将优先使用环境变量。
- 当我们在
db.yaml
中未设置name
时,输出将为db.name: mysqldb
。 - 当我们在
db.yaml
中设置了name
值为somedb
时,输出将为db.name: somedb
。
希望你会发现它有用!有关更多使用细节,请参阅Viper的README文件。
英文:
I recommend you use the awesome Viper package by spf13) to read conf files, it can solve your problem gracefully and you can use it to load many other type of conf files.
Solve your problem
- Get the package
go get github.com/spf13/viper
- conf file
Supposed you have conf file named db.yaml
:
db:
name: somedb
host: localhost
- code example
As we can see, once Viper loads the conf file, we can get values by key. A Yaml file will be parsed as a nested structure which you can unmarshal into a Golang struct, We should use viper.GetString("db.name")
to get the value, you can refer to this page to get more usage info.
import (
"fmt"
"github.com/spf13/viper"
)
func InitConf() {
viper.AutomaticEnv() // read system env
viper.SetConfigName("db") // conf file name to be load
viper.AddConfigPath(".") // conf file path
viper.SetDefault("db.name", "mysqldb") // you can set default da name value here
// do read conf file and handle error
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found; ignore error if desired
} else {
// Config file was found but another error was produced
}
}
fmt.Printf("db.name: %s", viper.GetString("db.name"))
}
viper.AutomaticEnv()
this method will read system env automatically, suppose you have an env named ENV_XXX
, then you can get it by viper.GetString("ENV_XXX")
. If the env name is the same as one of conf file key, viper uses the env first
- when we do not set the
name
indb.yaml
the output will bedb.name: mysqldb
- when we set the
name
value:somedb
in db.yaml the output will bedb.name: somedb
Hope you will find it useful! more details on usage see the Viper README file
答案3
得分: 0
我猜你的conf结构体可能是这样的:
type Db struct {
Name string
Host string
}
type Config struct {
Db *Db
}
所以要获取Dbname的默认变量,你必须像这样进行检查:
if conf.Db == nil || conf.Db.Name == "" {
conf.Db.Name = "test"
}
希望对你有帮助!
英文:
I guess you had a struct for your conf like this:
Db *struct{
Name string
Host string
}
so for retrieve the default variable of Dbname, you must check it like this:
if conf.Db == nil || conf.Db.Name == "" {
conf.Db.Name = "test"
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论