【问题标题】:Get environment variables using C code使用 C 代码获取环境变量
【发布时间】:2012-04-16 22:14:59
【问题描述】:

这里我写了一个 C 程序,它使用 system 调用来执行 hi.sh 文件。

这里我使用了. ./hi.sh,所以我想在同一个shell中执行这个脚本 然后尝试使用 getenv 函数获取环境变量,但在这里我得到的输出与我的预期不同。

hi.sh 文件包含

export TEST=10
return

意味着当我使用系统调用运行这个hi.sh 文件时,它的export TEST 在同一个shell 中将值设置为10。 在此之后,我试图获取这个变量值,但它给定了NULL 值。

如果我从. ./hi.sh 之类的控制台手动运行此脚本,那么它工作正常,我使用getenv("TEST") 函数得到TEST 的10 个值。

代码:

#include <stdio.h>
int main()
{
    system(". ./hi.sh");
    char *errcode;
    char *env = "TEST";
    int errCode;    
    errcode = getenv(env);
    printf("Value is = %s\n",errcode);
    if (errcode != NULL) {
        errCode =atoi(errcode);
        printf("Value is = %d\n",errCode);
    }
}

输出:

Value is = (null)

如何在程序 shell 中导出 TEST 变量?如果system() 在不同的shell 中执行命令,那么我如何使用C 程序代码获取由system() 调用调用的shell 导出的环境变量?

【问题讨论】:

    标签: c linux embedded


    【解决方案1】:

    子进程不能直接设置父进程的环境。因此,使用system()getenv() 的方法注定要失败。

    如果您尝试导入由脚本hi.sh 设置的选定变量,那么您有几个选择。您可以阅读脚本 hi.sh 并计算出它会将它们设置为什么(相当困难),或者您可以运行脚本并让您运行的代码报告您感兴趣的环境变量。

    假设hi.sh 设置$ENV1$ENV2。您可以使用popen() 将值返回到您的程序,并使用setenv() 设置程序的环境。概述:

    FILE *fp = popen(". ./hi.sh; echo ENV1=$ENV1; echo ENV2=$ENV2", "r");
    
    while (fgets(buffer, sizeof(buffer), fp) != 0)
    {
        ...split the buffer into env_name, env_value...
        setenv(env_name, env_value);
    }
    
    pclose(fp);
    

    请注意,我在回显信息中包含了变量名称;这简化了生活。如果你的变量列表变得笨拙,也许你运行". ./hi.sh; env" 来获取整个环境,然后读取每一行并从你的内置列表中计算出它是否是你想要使用的变量设置。或者,如果您喜欢的话,您也可以简单地重新设置整个环境。您应该检查setenv() 函数是否成功(成功时返回零)。您还应该检查popen() 是否成功(fp != 0)。在这种情况下,您可能可以使用strtok() 来查找将变量名与值分开的=;它在= 上践踏一个空字节,为您提供一个空终止名称和一个空终止值:

        char *env_name = strtok(buffer, "=");
        char *env_value = buffer + strlen(env_name) + 1;
        if (setenv(env_name, env_value) != 0)
            ...report trouble...
    

    【讨论】:

      【解决方案2】:

      像往常一样,手册页确实解释了这一点,但您需要非常仔细地阅读。

      DESCRIPTION
             system()  executes a command specified in command by calling /bin/sh -c
             command, and returns after the command has been completed.  During exe‐
             cution  of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT
             will be ignored.
      

      换句话说,system() 首先启动 /bin/sh,然后让 /bin/sh 启动你想要执行的任何命令。 所以这里发生的情况是,TEST 变量被导出到 /bin/sh shell,system() 调用隐式启动,而不是调用 system() 的程序。

      【讨论】:

      • 那么我怎样才能实现这个目标呢?
      • 如何将 TEST 变量导出到 Shell 程序中?
      • @user1089679 在运行 C 程序之前获取脚本(设置环境)。这就是环境变量的设计方式。
      【解决方案3】:

      另一种可能的解决方案是让您的程序exec 本身通过另一个shell。该外壳替换正在运行的程序,然后读取环境变量,然后用程序的新副本替换外壳。您需要告诉新副本它已经执行过一次,否则它只会循环执行一遍又一遍。您可以查找环境变量,或传递命令行标志。

      一个未经测试的例子:

      execl("/bin/sh", "-c", ". ./hi.sh; exec ./a.out --envset", NULL);
      

      您需要将 a.out 替换为真正的程序名称。您可能希望从 argv[0] 中提取它并传递 argv 数组的其余部分。但是您必须重新格式化参数以用作 shell 参数,因此需要根据需要引用它们等。

      【讨论】:

        【解决方案4】:

        您可以使用setenv() 在自己的进程中设置环境变量(system() 然后静默传递给子进程,或者使用fork()execve() 显式传递变量以运行shell 脚本.

        【讨论】:

        • 感谢您的回复。但是我必须使用系统调用来调用 shell 脚本,并且必须从脚本中设置环境变量。在此之后我想从 shell 获取环境变量
        • 这是不可能的。变量只能传递给新创建的进程,不能传回父进程。您的脚本应该生成一些输出,您可以使用 popen() 而不是 system() 来检索这些输出。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-04
        • 2013-07-01
        • 2021-02-01
        • 1970-01-01
        相关资源
        最近更新 更多