Can an executable dynamically resolve its location on the filesystem or its actual "resting place" vs just the working directory of the user?

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

Can an executable dynamically resolve its location on the filesystem or its actual "resting place" vs just the working directory of the user?

问题

如果我在/usr/bin中有一个可执行文件,并且在~/dev/wikis/目录下调用它(即user@HAL:~/dev/wikis$ the_executable),可执行文件中的ioutil.ReadFile("file.txt")函数将在/home/user/dev/wikis/file.txt中查找,但是否可能使其在不事先知道可执行文件将位于/usr/bin(它也可以位于/home/user/dev/my_program/the_executable)的情况下,查找/usr/bin/file.txt呢?

然后再增加一层复杂性,假设我通过/usr/bin中的一个符号链接调用可执行文件,而实际上可执行文件的源文件位于/home/user/dev/my_program/the_executable,在这种情况下,我希望程序动态地知道/home/user/dev/my_program/,而不是/usr/bin

**简而言之:**可执行文件如何动态解析其在文件系统中的位置或其实际的“所在位置”与用户的工作目录(可以通过os.Getwd()轻松获取,并且其他命令如ioutil.ReadFile使用它或使用类似的东西来解析路径)。

我最好的猜测是,我必须获取正在运行的程序的PID(os.Getpid),然后以某种方式使用该整数来访问有关在该PID下运行的程序实例的信息,希望该信息包含其目录的字符串,然后我可以使用该字符串。

英文:

If I have an executable in /usr/bin and call it while I'm located at ~/dev/wikis/ (that is user@HAL:~/dev/wikis$ the_executable), the ioutil.ReadFile("file.txt") function in the executable will look in /home/user/dev/wikis/file.txt, but is it possible to make it look in /usr/bin/file.txt instead without the user or developer knowing beforehand that the executable will be located in /usr/bin (it could just as well be located in /home/user/dev/my_program/the_executable)?

And then to add a layer of complexity, another situation, say I call the executable from a symbolic link in /usr/bin with the "source" of the executable actually being in /home/user/dev/my_program/the_executable, and I want the program to know about /home/user/dev/my_program/ in this case, dynamically, rather then /usr/bin.

In short: How can an executable dynamically resolve its location on the filesystem or its actual "resting place" vs the working directory of the user (which can easily be gotten through os.Getwd() and which other commands like ioutil.ReadFile use, or use something comparible, for resolving paths).

My best bet is that I have to get the PID of the running program (os.Getpid) and then somehow use that integer to access information about the instance of the program running under that PID, and hopefully that information contains a string of its directory which I can then use.

答案1

得分: 3

在Linux(以及其他类Unix系统)中,你会在/proc/pid/exe路径下找到一个指向实际可执行文件的符号链接,检查该链接将会给出你想要的结果,如果它是一个二进制文件的话。如果它是某种脚本,那么这个链接可能只会给出解释器。

但请注意,完全有可能在进程运行时启动该进程并删除可执行文件,这样会留下一个悬空的链接或者什么都没有。

英文:

In Linux (and perhaps in other Unixy systems) you'll find a symbolic link to the actual executable running as pid under /proc/pid/exe, checking that one will give what you want if it is a binary. If it is a script of some sort, that will probably just give the interpreter.

But note that it is perfectly possible to start a process and delete the executable while it is running, leaving either a dangling link or just nothing.

答案2

得分: 0

这将取决于编程语言,但据我所知,大多数编程语言都有一种方法来获取程序的“基本名称”,例如helloworld,或者完整路径,例如/usr/bin/helloworld。通常,这是作为程序的第一个参数提供的,由操作系统/运行时库/解释器等插入。例如,在C语言中,argv[0](由于在C语言中从0开始计数)给出当前程序的名称,但调用进程会初始化这个特殊参数,因此确切的格式可能会有所不同;在bash中,$0会展开为执行时给定的脚本路径(我想是这样的)。从这里可以看到:https://gobyexample.com/command-line-arguments,“os.Args提供对原始命令行参数的访问。请注意,此切片中的第一个值是程序的路径,os.Args[1:]保存程序的参数。”所以看起来你不需要担心/proc,但如果你感兴趣,可以参考https://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c

英文:

This will depend on the language but as far as I know most programming languages have a way to get either the 'basename' of the program, e.g. helloworld, or the full path, e.g. /usr/bin/helloworld. Often this is provided as the first argument to the program, inserted by the OS/runtime library/interpreter, etc. For example, in C, argv[0] (as we start counting from 0 in C) gives the name of the current program, but the calling process initialises this special argument so the exact format can vary, and in bash, $0 will expand into the path of the script as given when executed (I think). From here: https://gobyexample.com/command-line-arguments, "os.Args provides access to raw command-line arguments. Note that the first value in this slice is the path to the program, and os.Args[1:] holds the arguments to the program." So it appears you don't need to worry about /proc but if you're interested, https://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c

答案3

得分: 0

导出的变量os.Args(一个切片:[]string)保存了程序的参数,其中第一个元素是带有完整路径的可执行文件名。

如果可执行文件不是符号链接,你可以使用pathfilepath包来获取可执行文件所在的文件夹,像这样:

folder := filepath.Dir(os.Args[0])

你可以使用os.Readlink()来解析符号链接。

要测试可执行文件是否为符号链接,可以使用os.Lstat(),它不会尝试跟踪链接(与os.Stat()相反)。

所以你的最终版本应该是这样的:

s := os.Args[0]
fi, err := os.Lstat(s)
if err != nil {
    panic(err) // 获取状态失败
}

// 检查是否为符号链接,如果是,则尝试解析它
if fi.Mode()&os.ModeSymlink != 0 {
    if s, err = os.Readlink(s); err != nil {
        panic(err) // 解析符号链接失败
    }
}
s = filepath.Dir(s) // 我们只需要文件夹部分
英文:

The exported variable os.Args (which is a slice: []string) holds the program arguments, its first element being the executable name with full path.

If the executable is not a symlink, you can use the path or filepath packages to get the folder of the executable like this:

folder := filepath.Dir(os.Args[0])

And you can use os.Readlink() to resolve a symbolic link.

And to test if your executable is a symlink, you can use os.Lstat() which makes no attempt to follow a link (as opposed to os.Stat()).

So your final version should look like this:

s := os.Args[0]
fi, err := os.Lstat(s)
if err != nil {
	panic(err) // Failed to get stats
}

// Check if it's a symlink and if so, try to resolve it
if fi.Mode()&os.ModeSymlink != 0 {
	if s, err = os.Readlink(s); err != nil {
		panic(err) // Failed to resolve symlink
	}
}
s = filepath.Dir(s) // We only want the folder part

huangapple
  • 本文由 发表于 2015年10月16日 07:55:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/33160412.html
匿名

发表评论

匿名网友

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

确定