如何从不同的路径调用二进制文件并打开文件。

huangapple go评论86阅读模式
英文:

How to call the binary from a different path and open a file

问题

问题:如何解决这个问题?

回答:要解决这个问题,你可以尝试以下几种方法:

  1. 使用绝对路径:在loadConfigFile()函数中,将ConfigFileEnv的值改为配置文件的绝对路径,而不是相对路径。例如,你可以将其设置为/home/user/Documents/ip-updater-opendns/config.json

  2. 使用相对路径:如果你希望程序在任何目录下都能正常工作,可以使用相对于可执行文件的路径。你可以使用os.Executable()函数获取可执行文件的路径,并将其与配置文件的相对路径拼接起来。

    func loadConfigFile() Config {
        const ConfigFileRel = "config.json"
        var config Config
    
        exePath, err := os.Executable()
        if err != nil {
            panic(fmt.Errorf("couldn't get executable path: %w", err))
        }
    
        configFile := filepath.Join(filepath.Dir(exePath), ConfigFileRel)
    
        file, err := os.Open(configFile)
        // ...
    }
    

    这样,程序就可以在任何目录下正确地找到配置文件。

  3. 设置工作目录:在程序开始时,可以使用os.Chdir()函数将工作目录更改为配置文件所在的目录。这样,无论从哪个目录运行程序,它都会将工作目录更改为正确的路径。

    func main() {
        exePath, err := os.Executable()
        if err != nil {
            panic(fmt.Errorf("couldn't get executable path: %w", err))
        }
    
        configFileDir := filepath.Dir(exePath)
        err = os.Chdir(configFileDir)
        if err != nil {
            panic(fmt.Errorf("couldn't change working directory: %w", err))
        }
    
        // ...
    }
    

    这样,程序在运行之前会将工作目录更改为配置文件所在的目录,确保能够正确读取配置文件。

希望这些方法能够帮助你解决问题!

英文:
Context

I created a simple program to auto update my Public IP address on OpenDNS.
To be able to use the program I need the credentials for OpenDNS site, so I created a config.json file to be able to read the credentials from it.

Inside the Go project folder, calling the binary, works fine
./main
http return code: 200 defining the new IP: 123.123.123.123
If I change to another folder (let's say my /home/user for example), the binary can't open the file anymore
./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
I'm opening the file the following way:
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
}
Why do I want to call my binary from another folder?

Because I want this program to be executed by cronjob every 5 minutes.

So my question is, how to solve this problem?

答案1

得分: 2

当你在Go项目中运行时,config.json文件位于当前目录,因此相对路径config.json有效。当你从其他目录运行时,这个条件不再成立,无法找到config.json

    const ConfigFileEnv = "config.json"

你硬编码了配置文件的名称,所以它必须在当前工作目录中。为什么不将配置文件的名称作为程序的参数呢?

    if len(os.Args) < 2 {
      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

(注意,在路径前面添加./一次或多次是多余的。相对路径始终相对于.,即当前工作目录)。

另一种方法是在执行程序之前,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

你还可以查看https://stackoverflow.com/questions/24069664/what-does-go-install-do,了解如何使go install适用于你的项目,这将进一步区分开发项目和在“生产”中使用的项目。

英文:

When you run in your go project, config.json is in the current directory, so the relative path config.json works. When you run from other directories, that is no longer true, and config.json cannot be found.

    const ConfigFileEnv = &quot;config.json&quot;

You hard coded the config file name so it must be in your current working directory. Why not put the name of the configuration file in an argument to the program?

    if len(os.Args) &lt; 1 {
      panic(&quot;First argument should be config file path&quot;)
    }
    var ConfigFileEnv = os.Args[1] 

When you run it from your project directory you can use a relative path:

./main config.json

When you run it from a different directory (or your cron) you can use a different path, relative to the home directory:

Documents/ip-updater-opendns/main Documents/ip-updater-opendns/config.json

(note that prepending ./ to a path 1 or more times is redundant. Relative paths are always relative to ., the current working directory).

The alternative would be for the cron job to change the directory in a shell before executing your program:

*/5 * * * * bash -c &quot;cd Documents/ip-updater-opendns/; exec ./main&quot;

But I wouldn't do that. I question the value of hard coding a config file name. It doesn't make sense to impose the limitation of only being able to read config.json from the current directory. I would pass that either as an argument or an environment variable. Then you could also configure multiple different configuration files if you happened to have multiple OpenDNS domain names.

To take that consideration one step further, does it really make a lot of sense to put config.json into your project directory? It might make more sense to put it elsewhere, like ~/.opendns-config.json or somewhere in /var perhaps. The project directory is pretty irrelevant once the go program has been compiled. I probably would put main somewhere like /usr/local/bin/ myself - and name it something better than main - maybe opendns-update or something like that. Then the cron looks somethign like:

*/5 * * * * opendns-update /home/LUCAS.VARELA/.opendns-config.json

You might also want to take a look at https://stackoverflow.com/questions/24069664/what-does-go-install-do which explains how you could make go install work for your project, which would further differentiate between the development project and its use in "production".

huangapple
  • 本文由 发表于 2021年10月24日 23:20:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/69698153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定