Linux 使用 C 代码获取环境变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9990214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get environment variables using C code
提问by user1089679
Here I wrote a C program which executes hi.sh
file using system
call.
在这里我写了一个 C 程序,它hi.sh
使用system
调用来执行文件。
Here I used . ./hi.sh
so I want to execute this script in the same shell
and then try to get environment variable using getenv function, but here I am getting different output from what I expected.
在这里我使用了. ./hi.sh
所以我想在同一个 shell 中执行这个脚本,然后尝试使用 getenv 函数获取环境变量,但在这里我得到了与我预期不同的输出。
The hi.sh
file contains
该hi.sh
文件包含
export TEST=10
return
Means when I run this hi.sh
file using system call, its export TEST
sets the value to 10 in same shell.
After this, I am trying to get this variable value but its given NULL
value.
意味着当我hi.sh
使用系统调用运行这个文件时,它export TEST
在同一个 shell 中将值设置为 10。在此之后,我试图获取这个变量值,但它的给定NULL
值。
And if I run this script manually from console like . ./hi.sh
then it works fine and I get 10 value of TEST
using getenv("TEST")
function.
如果我从控制台手动运行这个脚本,. ./hi.sh
那么它工作正常,我得到 10 个TEST
使用getenv("TEST")
函数的值。
Code:
代码:
#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);
}
}
output :
输出 :
Value is = (null)
How can I export TEST variable in program shell? If system()
executes commands in different shell then how can I use C program code to get an environment variable which is exported by the shell invoked via a system()
call?
如何在程序 shell 中导出 TEST 变量?如果system()
在不同的 shell 中执行命令,那么我如何使用 C 程序代码来获取由通过调用调用的 shell 导出的环境变量system()
?
采纳答案by Kristof Provost
As usual, the man page does explain this, but you need to read it very carefully.
像往常一样,手册页确实解释了这一点,但您需要非常仔细地阅读它。
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.
In other words, system() first starts /bin/sh, and then has /bin/sh start whatever command you want to execute. So what happens here is that the TEST variable is exported to the /bin/sh shell the system() call implicitly started, but not to the program which called system().
换句话说,system() 首先启动 /bin/sh,然后让 /bin/sh 启动您想要执行的任何命令。所以这里发生的是 TEST 变量被导出到 system() 调用隐式启动的 /bin/sh shell,而不是被调用 system() 的程序。
回答by Simon Richter
You can either set the environment variable in your own process using setenv()
(which system()
then silently passes on to child processes, or explicitly pass the variables by using fork()
and execve()
to run the shell script.
您可以在自己的进程中设置环境变量 using setenv()
(system()
然后静默传递给子进程,或者通过使用fork()
和execve()
运行 shell 脚本显式传递变量。
回答by Jonathan Leffler
The child process cannot directly set the parent process's environment. The approach using system()
and getenv()
is doomed to fail, therefore.
子进程不能直接设置父进程的环境。因此,使用system()
和的方法getenv()
注定要失败。
If you are trying to import selected variables set by the script hi.sh
, then you have a couple of choices. Either you can read the script hi.sh
and work out what it would set them to (rather hard), or you can run the script and have the code you run report back on the environment variables of interest.
如果您尝试导入由脚本设置的选定变量hi.sh
,那么您有几个选择。您可以阅读脚本hi.sh
并计算出它会将它们设置为什么(相当困难),或者您可以运行脚本并让您运行的代码报告感兴趣的环境变量。
Suppose that hi.sh
sets $ENV1
and $ENV2
. You can use popen()
to get the values back to your program, and setenv()
to set your program's environment. In outline:
假设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);
Note that I included the variable name in the echoed information; this simplifies life. If your list of variables gets unwieldy, maybe you run ". ./hi.sh; env"
to get the entire environment, and then read each line and work out from your built-in list whether its a variable setting you want to use or not. Or you can simply set your entire environment again, if that pleases you. You should check that the setenv()
function succeeded (it returns zero when it does succeed). You should also check that the popen()
was successful (fp != 0
). In this context, you probably can use strtok()
to look for the =
separating the variable name from the value; it tramples a null byte over the =
, giving you a null terminated name and a null terminated value:
请注意,我在回显信息中包含了变量名称;这简化了生活。如果您的变量列表变得笨拙,也许您运行". ./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...
回答by Zan Lynx
Another possible solution is to have your program exec
itself through another shell. That shell replace the running program, then read the environment variables and then replace shell with a new copy of the program. You need to tell the new copy that it has already done an exec or it will just loop doing it over and over. You could look for the environment variable, or pass a command-line flag.
另一种可能的解决方案是让您的程序exec
本身通过另一个 shell。该 shell 替换正在运行的程序,然后读取环境变量,然后用程序的新副本替换 shell。您需要告诉新副本它已经执行了 exec,否则它会一遍又一遍地循环执行。您可以查找环境变量,或传递命令行标志。
An untested example:
一个未经测试的例子:
execl("/bin/sh", "-c", ". ./hi.sh; exec ./a.out --envset", NULL);
You would need to replace a.out with whatever the real program name is. You would probably want to extract it from argv[0] and also pass the rest of the argv array. But you have to reformat the arguments to work as shell arguments, so they need to be quoted as necessary, etc.
您需要将 a.out 替换为任何真正的程序名称。您可能希望从 argv[0] 中提取它并传递 argv 数组的其余部分。但是您必须重新格式化参数以用作 shell 参数,因此需要根据需要引用它们,等等。