为什么 posix_spawn() 在 popen() 工作的地方失败?

Why does posix_spawn() fail where popen() works?

我在我的 C 程序中成功地使用了 popen() 到 运行 命令。据我了解,它在幕后使用 fork()exec() (或它们的变体)。这非常有效:

FILE *fd = popen("xterm", "r");
pclose(fd);

... 将按预期调出一个新的 xterm window。

现在我正在尝试使用 posix_spawn() 实现相同的目的,据我所知这可能对资源更友好,尤其是如果我们不打算与新的子进程进行通信时:

/* p.we_wordv contains the argv, index 0 holds the actual command */
pid_t pid;
posix_spawnp(&pid, p.we_wordv[0], NULL, NULL, p.we_wordv, NULL);

... 但是,对于 xterm 作为命令,在父级的输出中产生以下内容:

xterm: Xt error: Can't open display:
xterm: DISPLAY is not set

尝试启动其他进程会产生其他错误消息,无声地失败,或者在某些情况下,如 ls,按预期工作。这让我很难真正看到一个模式。

你能指出是什么导致第二种方法的行为与第一种不同吗?

消息 DISPLAY is not set 告诉您 xterm 没有找到 DISPLAY 环境变量 。所有 graphical-output 程序都使用此环境变量连接到您的屏幕。

它没有找到变量,因为环境是空的(这是您 posix_spawnp 函数调用中的最后一个 NULL)。好像popen复用了当前进程的环境,所以没有这个问题。

您可能想要传递一个 manually-created 环境,只包含需要的东西,或者只传递您的进程拥有的任何环境。后者更灵活(xterm 将从您的进程继承各种配置设置,而进程从您的 shell 继承它们)但可能存在安全风险。

要访问进程的环境,请使用 environ 全局变量或更改 main 函数以接收附加参数:

int main(int argc, char *argv[], char *envp[])
{
    ...
    posix_spawnp(&pid, p.we_wordv[0], NULL, NULL, p.we_wordv, envp);
}