使用C代码获取环境variables

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

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

hi.sh文件包含

 export TEST=10 return 

意思是当我使用系统调用运行这个hi.sh文件时,它的export TEST将值设置为10在同一个shell中。 在此之后,我试图得到这个variables值,但它的给定的NULL值。

如果我从控制台手动运行这个脚本. ./hi.sh . ./hi.sh然后它工作正常,我得到10使用getenv("TEST")function的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中导出TESTvariables? 如果system()在不同的shell中执行命令,那么如何使用C程序代码来获取由system()调用调用的shell导出的环境variables?

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

 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变量被导出到system()调用隐式启动的/ bin / sh shell中,而不是被调用system()的程序。

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

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

一个未经测试的例子:

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

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

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