可执行文件能否动态解析其在文件系统上的位置或其实际 "resting place" 与用户的工作目录?
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
中的情况下使其在 /usr/bin/file.txt
中查找(它也可以是位于 /home/user/dev/my_program/the_executable
)?
然后添加一层复杂性,另一种情况,假设我从 符号 link 中调用可执行文件 /usr/bin
38=] 的可执行文件实际上在 /home/user/dev/my_program/the_executable
中,我希望程序在这种情况下动态地了解 /home/user/dev/my_program/
,而不是 /usr/bin
.
简而言之: 可执行文件如何动态解析其在文件系统上的位置或其实际 "resting place" 与用户的工作目录(可以轻松获取)通过 os.Getwd()
以及 ioutil.ReadFile
等其他命令使用或使用类似的东西来解析路径)。
我最好的选择是我必须获得 运行 程序的 PID (os.Getpid
),然后以某种方式使用该整数来访问有关程序实例的信息 运行 在该 PID 下,希望该信息包含其目录的字符串,然后我可以使用它。
这将取决于语言,但据我所知,大多数编程语言都有办法获取程序的 'basename',例如helloworld,或完整路径,例如/usr/bin/helloworld。这通常作为程序的第一个参数提供,由 OS/runtime library/interpreter 等插入。例如,在 C 中,argv[0](因为我们在 C 中从 0 开始计数)给出当前程序的名称,但调用进程会初始化此特殊参数,因此确切的格式可能会有所不同,并且在 bash 中,$0 将扩展为执行时给定的脚本路径(我认为)。来自这里: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, How do I find the location of the executable in C?
在 Linux 中(也许在其他 Unixy 系统中)你会发现一个符号 link 到实际的可执行文件 运行 作为 pid
在 /proc/pid/exe
,如果它是一个二进制文件,检查它是否会给出你想要的。如果它是某种脚本,那可能只会给解释器。
但请注意,完全有可能在 运行 时启动进程并删除可执行文件,留下悬空的 link 或什么也没有。
导出的变量os.Args
(它是一个切片:[]string
)保存程序参数,它的第一个元素是带有完整路径的可执行文件名。
如果可执行文件不是 symlink,您可以使用 path
or filepath
包来获取可执行文件的文件夹,如下所示:
folder := filepath.Dir(os.Args[0])
并且您可以使用 os.Readlink()
来解析符号 link。
并且要测试您的可执行文件是否是 symlink,您可以使用 os.Lstat()
which makes no attempt to follow a link (as opposed to os.Stat()
).
所以你的最终版本应该是这样的:
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
如果我在 /usr/bin
中有一个可执行文件并在我位于 ~/dev/wikis/
(即 user@HAL:~/dev/wikis$ the_executable
)时调用它,则可执行文件中的 ioutil.ReadFile("file.txt")
函数将在 /home/user/dev/wikis/file.txt
中查找,但是否可以在用户或开发人员事先不知道可执行文件将位于 /usr/bin
中的情况下使其在 /usr/bin/file.txt
中查找(它也可以是位于 /home/user/dev/my_program/the_executable
)?
然后添加一层复杂性,另一种情况,假设我从 符号 link 中调用可执行文件 /usr/bin
38=] 的可执行文件实际上在 /home/user/dev/my_program/the_executable
中,我希望程序在这种情况下动态地了解 /home/user/dev/my_program/
,而不是 /usr/bin
.
简而言之: 可执行文件如何动态解析其在文件系统上的位置或其实际 "resting place" 与用户的工作目录(可以轻松获取)通过 os.Getwd()
以及 ioutil.ReadFile
等其他命令使用或使用类似的东西来解析路径)。
我最好的选择是我必须获得 运行 程序的 PID (os.Getpid
),然后以某种方式使用该整数来访问有关程序实例的信息 运行 在该 PID 下,希望该信息包含其目录的字符串,然后我可以使用它。
这将取决于语言,但据我所知,大多数编程语言都有办法获取程序的 'basename',例如helloworld,或完整路径,例如/usr/bin/helloworld。这通常作为程序的第一个参数提供,由 OS/runtime library/interpreter 等插入。例如,在 C 中,argv[0](因为我们在 C 中从 0 开始计数)给出当前程序的名称,但调用进程会初始化此特殊参数,因此确切的格式可能会有所不同,并且在 bash 中,$0 将扩展为执行时给定的脚本路径(我认为)。来自这里: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, How do I find the location of the executable in C?
在 Linux 中(也许在其他 Unixy 系统中)你会发现一个符号 link 到实际的可执行文件 运行 作为 pid
在 /proc/pid/exe
,如果它是一个二进制文件,检查它是否会给出你想要的。如果它是某种脚本,那可能只会给解释器。
但请注意,完全有可能在 运行 时启动进程并删除可执行文件,留下悬空的 link 或什么也没有。
导出的变量os.Args
(它是一个切片:[]string
)保存程序参数,它的第一个元素是带有完整路径的可执行文件名。
如果可执行文件不是 symlink,您可以使用 path
or filepath
包来获取可执行文件的文件夹,如下所示:
folder := filepath.Dir(os.Args[0])
并且您可以使用 os.Readlink()
来解析符号 link。
并且要测试您的可执行文件是否是 symlink,您可以使用 os.Lstat()
which makes no attempt to follow a link (as opposed to os.Stat()
).
所以你的最终版本应该是这样的:
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