Here I wrote a C program which executes hi.sh
file using system
call.
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.
The hi.sh
file contains
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.
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.
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?
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.
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.
The child process cannot directly set the parent process's environment. The approach using system()
and getenv()
is doomed to fail, therefore.
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.
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:
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:
char *env_name = strtok(buffer, "=");
char *env_value = buffer + strlen(env_name) + 1;
if (setenv(env_name, env_value) != 0)
...report trouble...
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().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With