如果脚本使用#!/usr/bin/env foo,如何在Linux中的C中找到解释器二进制文件的完整路径

问题描述 投票:0回答:1

我正在 Linux 中用 C 语言编写新的脚本解释器。它位于 ~/foo 目录中:

~/foo          - directory
~/foo/foo.c    - source
~/foo/foo      - compiled C binary
~/foo/data.txt - file with data the interpreter will need

我希望能够从命令行运行解释器,所以我将符号链接放入 ~/bin (我在 PATH 中):

~/bin/foo      - symlink to "~/foo/foo" binary

这有效,当我在终端中输入“foo”时,它会运行解释器。现在我希望能够使用“#!/usr/bin/env foo”hashbang 运行脚本。我在 ~/test.fs 中编写了这个可执行脚本:

#!/usr/bin/env foo
some foo code

当我使用 ./test.fs 运行脚本时,它可以工作,它是使用 foo 解释器执行的。然而,在解释器本身中,如果我打印 argv[0] 它只包含“foo”。我尝试使用 realpath(argv[0], ...) 函数,但它找不到真正的路径:

char resolved_path[MAXPATHLEN];
if(realpath(argv[0], resolved_path)) {
    printf("resolved_path=%s\n", resolved_path);
}

realpath(“foo”,resolved_path) 不会返回 true,因为“foo”位于 ~/bin 中,但运行脚本时我位于其他目录中。

在解释器中,我只需要找到“foo”二进制文件的绝对路径,即使它是通过 /usr/bin/env foo 执行的,并且 ~/bin/foo 是符号链接。

如果我知道 ~/bin/foo 的绝对路径,我可以使用 readlink 来查找该符号链接的目标,但我不知道如何从“foo”到“~/bin/foo”。

这里是翻译来源:

#include <stdio.h>
#include <sys/param.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
    printf("argv[0]=%s\n", argv[0]);
    char resolved_path[MAXPATHLEN];
    if(realpath(argv[0], resolved_path)) {
        printf("resolved_path=%s\n", resolved_path);
    }
    printf("actual interpreter stuff goes here...\n");
    return 0;
}

总结:

  1. 将 argv[0] 读取为“foo”
  2. 发现执行的文件实际上是“~/bin/foo”
  3. 如果是符号链接查找目标
  4. 使用 realpath 查找二进制文件的绝对路径

我被困在第2点了。

我无法将数据放入 /usr/share/... 或其他目录,因为这仍在开发中,我经常需要编辑文件,并且同时需要多个版本,所以最好的方法是将数据与二进制。每个版本都会在二进制文件旁边有数据,这样我就可以有 ~/foo1/foo、~/foo2/foo 等。 ~/foo1/foo 将读取 ~/foo1/data.txt 和 ~/foo2/foo 将读取 ~/foo2/data2.txt。

c linux bash symlink hashbang
1个回答
0
投票

如何从“foo”到“~/bin/foo”。

在 Linux 上,

readlink("/proc/$PID/exe")
是指向可执行位置的符号链接。

如果不在 Linux 上,您将

getenv("PATH")
然后在
:
上拆分,并为每个目录检查
dir/foo
是否存在。您找到的第一个就是那个。

记住处理错误。不仅可执行文件本身可能不存在,而且

argv[0]
也可能为 NULL 或空或任何东西。

© www.soinside.com 2019 - 2024. All rights reserved.