使用C代码获取环境变量

时间:2012-04-03 09:07:01

标签: c linux embedded

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

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

hi.sh文件包含

export TEST=10
return

表示当我使用系统调用运行此hi.sh文件时,其export TEST在同一个shell中将值设置为10。 在此之后,我试图获取此变量值,但其值为NULL

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

代码:

#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导出的环境变量?

4 个答案:

答案 0 :(得分:9)

子进程无法直接设置父进程的环境。因此,使用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...

答案 1 :(得分:7)

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

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()的程序。

答案 2 :(得分:1)

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

一个未经测试的例子:

exec

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

答案 3 :(得分:0)

您可以使用setenv()在其自己的流程中设置环境变量(system()然后以静默方式传递给子流程,或使用fork()和{{显式传递变量1}}运行shell脚本。