在这里我写了一个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脚本。