上下文
我创建了一个简单的程序来自动更新我在OpenDNS上的公共IP地址。为了能够使用该程序,我需要OpenDNS站点的凭据,所以我创建了一个config.json文件,以便能够从中读取凭据。
在Go项目文件夹中,调用二进制文件,工作正常
./main
http return code: 200 defining the new IP: 123.123.123.123
如果我更改到另一个文件夹(例如my/home/user),二进制文件将无法再打开该文件
./Documents/ip-updater-opendns/main
panic: couldn't open config file config.json: open config.json: no such file or directory
goroutine 1 [running]:
main.loadConfigFile()
/home/user/Documents/ip-updater-opendns/main.go:50 +0x1e6
main.main()
/home/user/Documents/ip-updater-opendns/main.go:25 +0x45
我以以下方式打开文件:
func loadConfigFile() Config {
const ConfigFileEnv = "config.json"
var config Config
file, err := os.Open(ConfigFileEnv)
if err != nil {
panic(fmt.Errorf("couldn't open config file %s: %w", ConfigFileEnv, err))
}
err = json.NewDecoder(file).Decode(&config)
if err != nil {
panic(fmt.Errorf("couldn't decode config file %s as Json: %w", ConfigFileEnv, err))
}
return config
}
为什么要从另一个文件夹调用二进制文件
因为我希望cronjob每5分钟执行一次这个程序。
所以我的问题是,如何解决这个问题
在go项目中运行时,config.json
在当前目录中,因此相对路径config.json
有效。当您从其他目录运行时,这将不再是真的,并且找不到config.json
。
const ConfigFileEnv = "config.json"
您对配置文件名进行了硬编码,使其必须位于当前工作目录中。为什么不把配置文件的名称放在程序的参数中呢?
if len(os.Args) < 1 {
panic("First argument should be config file path")
}
var ConfigFileEnv = os.Args[1]
当你从项目目录中运行它时,你可以使用一个相对路径:
./main config.json
当你从不同的目录(或你的cron)运行它时,你可以使用不同的路径,相对于主目录:
Documents/ip-updater-opendns/main Documents/ip-updater-opendns/config.json
(请注意,将./
前置到路径1次或多次是多余的。相对于当前工作目录.
,相对路径总是)。
另一种选择是cron作业在执行程序之前更改shell中的目录:
*/5 * * * * bash -c "cd Documents/ip-updater-opendns/; exec ./main"
但我不会那样做。我质疑硬编码配置文件名的价值。强加只能从当前目录读取config.json
的限制是没有意义的。我会把它作为一个参数或一个环境变量来传递。如果你碰巧有多个OpenDNS域名,你也可以配置多个不同的配置文件。
更进一步地考虑,将config.json
放入项目目录真的有意义吗?把它放在其他地方可能更有意义,比如~/.opendns-config.json
或/var
中的某个地方。一旦编译了go程序,项目目录就变得非常不相关了。我可能会把main
放在类似/usr/local/bin/
的地方——并把它命名为比main
更好的东西——也许是opendns-update
或类似的东西。然后cron看起来有点像:
*/5 * * * * opendns-update /home/LUCAS.VARELA/.opendns-config.json
你可能还想看看go install的作用是什么?它解释了如何使go install
为您的项目工作,这将进一步区分开发项目及其在";生产";。