【问题标题】:How to change environment variable in shell executing a C program from that C program?如何在从该 C 程序执行 C 程序的 shell 中更改环境变量?
【发布时间】:2014-04-20 13:41:42
【问题描述】:

我想在 C 程序中更改 PATH 变量的值,然后在我运行该程序的 shell 中查看更改后的值。

做这样的事情,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main () {

    char *path = getenv ("PATH");
    printf ("%s\n\n", path);
    setenv ("PATH", strcat (path, ":~/myNewPath/"), 1);
    printf ("%s\n\n", path);

    int pid = fork ();
    if (pid == -1)
        abort ();
    if (pid == 0) {

    } else {
        // use execlp? how? source? any hints?
    }

    return 0;
}

如果我在exec* 系统调用中使用source 命令。在 shell 中向后更新这个 PATH 变量的语法是什么?

【问题讨论】:

  • 注意:setenv ("PATH", strcat (path, ":~/myNewPath/"), 1); 可能会出现段错误。
  • @wildplasser 不,不会的。为什么?
  • 因为您不能安全地将字符附加到 getenv() 返回的指针值所指向的字符串。如果您的 stcat() 没有段错误,那纯粹是巧合/运气。另外:getenv() 可以返回 NULL。
  • wildplasser 非常正确:它可能 不会 出现段错误,因为字符串位于更大的可写内存区域中(如我链接到的 ABI 文档中所述),但它可能覆盖相邻的数据(很可能是其他环境字符串)。
  • 还有一个额外的问题:波浪号不会被扩展,因为没有涉及到 {ksh,bash} shell。 (Linux手册页对此相当模糊)

标签: c shell unix


【解决方案1】:

这是不可能的。子进程无法更改其父进程的环境变量。

要了解为什么不可能,看execve的签名

int execve(const char *program, char *const *argv, char *const *envp);

在 Unix 系统上与 maintrue 签名配对

int main(int argc, char **argv, char **envp);

也许您开始明白,就内核而言,环境变量是第二组命令行参数。它们似乎可以通过getenvsetenv等独立访问,并且似乎从父级继承到子级,这是由C库维护的一种错觉。

有关其工作原理的更多详细信息,请研究the x86-64 ELF ABI specification, section 3.4.1 "Initial Stack and Register State",特别注意图 3.9,该图显示了由execve 复制到新创建的堆栈上的数据布局。 (链接的文档特定于一种 CPU 架构,但其工作方式在现代 Unix 中通常是一致的;细节当然会因 CPU 和操作系统而异。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-23
    • 2021-12-29
    • 2016-12-26
    • 2014-10-14
    • 2014-03-06
    相关资源
    最近更新 更多