【问题标题】:Modify enviroment variable with putenv in C在 C 中使用 putenv 修改环境变量
【发布时间】:2022-01-09 08:31:29
【问题描述】:

我正在用 C 语言制作自己的 shell,我被要求使用函数 putenv(char*) 修改环境变量,并且我已经实现了以下代码:

char *string = NULL;
    if ((string = (char *)malloc(strlen(tokens[2])+strlen(tokens[3])+2)) == NULL){
        perror("Error malloc");
        return 0;
    }
    strcpy(string, tokens[2]);
    strcat(string, "=");
    strcat(string, tokens[3]);
    putenv(string);

tokens[2] 和 tokens[3] 分别是变量的名称和我想给它的新值。 我的问题是,这只有在我要求从 extern char **environ 中列出环境时才有效,但是,当我从 main (char *envp[]) 的第三个参数中列出它时,cange 似乎不起作用。

有谁知道我如何告诉 putenv() 函数在两者中都进行更改?

我使用的列出环境的两种方式是:

void ShowEnviroment (char **enviroment, char * name_enviroment) 
{
    int i=0;
    while (enviroment[i]!=NULL) {
        printf ("%p->%s[%d]=(%p) %s\n", &enviroment[i],
                name_enviroment, i, enviroment[i], enviroment[i]);
        i++;
    }
}

参数enviroment 可以是environ(定义为extern char **environ)(它工作正常)或&envp(main 的第三个参数)(似乎没有显示变化的那个)

【问题讨论】:

  • envp 的参数 main 是来自父进程的输入环境only。而且你真的不应该使用envp environ。 POSIX 标准本身建议只使用getenv 来访问进程环境。
  • string = malloc(); strcpy(string... 无效。在 malloc 之后,string 不是以 null 结尾的字符串,所以不能使用 strcpy。在strcpy 之前需要string[0] = '\0'(或者只使用sprintf
  • @WilliamPursell No strcpy 没问题,因为 stringdestination(并且其内容被覆盖)。也许您正在考虑strcat,其中目标必须是正确的以空字符结尾的字符串?
  • @Someprogrammerdude 是的,我在想strcat。屏幕太多,咖啡太少......不过,我肯定更喜欢sprintf
  • The Glibc documentation indicates that envp has the same value as environ。当然,这必须被解释为这些的 initial 值。如果添加额外的环境变量,那么可能需要分配不同的、更大的空间,这似乎是合理的。在这种情况下,人们会期望 environ 会更新,但 envpmain 的本地,因此无法(自动)更新。

标签: c linux shell variables


【解决方案1】:

您的程序运行良好,符合预期。 envp 是程序启动时environ 的副本,并且可能与environ 不同,之后永远不会更新。

要运行命令,shell(例如您正在编写的那个)使用 fork() + execv() 的组合 -- 并且 manual on execv 指出

对于那些不包含 envp 指针的表单(execl()、execv()、execlp() 和 execvp()),新进程映像的环境应取自调用进程中的外部变量 environ。

...完全没有提及依赖您收到的envp,而不是您可能制造的来传递您的任何环境变量在使用exec* 变体时选择您的子进程,确实将修改后的环境变量作为参数。

附带说明,使用setenv()putenv 有两个优点,因此我会推荐它:

  • 无论你传递给putenv,都必须及时坚持;你传递给setenv 的任何东西都会被复制,所以你不需要管理它的内存。
  • 因此,setenv(char *key, char *value, int replace) 意味着对您的责任更少(并且无需 malloc、strcat 等)。

两者都会为您修改environ。请注意,您不应该直接写environ(但阅读它很好,并且需要,因为没有lsenv 函数可以列出 可用的环境变量);注意this warning

任何直接修改环境变量指向的指针的应用程序都有未定义的行为

【讨论】:

  • “不要使用putenv(),而是使用setenv()”有点强。 “你不应该直接访问environ”也是如此。如果您满足于适应 putenv() 的特定特征,则没有特别的理由不使用它。并且假设您使用 Unix,您可以通过environ 安全地读取环境;您只是不能通过environ修改它。
  • 修正了措辞以恭敬地更喜欢sentenv 而不是putenv,并指出阅读 environ 不仅很好,而且在许多用例中也是必需的;写的时候还是UB
猜你喜欢
  • 2017-07-11
  • 2016-06-25
  • 2020-09-10
  • 2017-07-16
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多