LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   setenv within a program doesn't last (https://www.linuxquestions.org/questions/programming-9/setenv-within-a-program-doesnt-last-172991/)

mvt 04-21-2004 03:35 PM

setenv within a program doesn't last
 
I wrote a C++ program which calls setenv() to change
the "path" environment variable. Within the program
I can then call getenv("PATH") and see the new
value.

But after the program exits, if I list the environment
variables using the tcsh command: setenv | grep -i path
I see the old path, not the one newly set.

Apparently the program is run with a copy of the
environment, which is modified and then discarded.

Any ideas how to make this program work?
I want the path changed within the shell after the
program terminates.

Note: I am using the setenv() command described in
section 3 of the man pages (man 3 setenv).
I also tried system("setenv path=(/bin /sbin)");
but it failed the same way.

Thanks,
Mark

Red Hat Linux version 9
gcc compiler
tcsh shell used

jim mcnamara 04-21-2004 03:55 PM

When you run a program, it runs in it's own separate sub-process.
When the sub-process exits, then all of the environment variables exit with it.

You return to the parent process, which never saw those changes.

If you want to set envrionment variables that stick around, you probably want to try using a simple script -- then execute the script with dot notation like this:
Code:

.  myscript.shl

kebabhead 04-21-2004 04:24 PM

Hi, I think what you are trying to do willl not work (if I'm wrong I'd love to know the answer!). Since your program is creating a child process which is then used to create the variable using setenv, then when this process exits the enviroment change is lost, it's said much better here:
"A script can export variables only to child processes, that is, only to commands or processes which that particular script initiates. A script invoked from the command line cannot export variables back to the command line environment. Child processes cannot export variables back to the parent processes that spawned them."
Advanced Bash Cripting Guide Ch 4.4

Cheers

Hko 04-21-2004 04:26 PM

Quote:

Apparently the program is run with a copy of the
environment, which is modified and then discarded.
Yes, that is exactly what happens. Only the program itself and its child processes (if the env. var. is exported) have the changed or added env. var. available.

What you could do to fix it is, instead of exiting your program, replacing it with a new shell process. For example: (C..., not C++. Sorry) :
Code:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
        char *shell;
       
        /* Get the path of the current shell to start it later */
        shell = getenv("SHELL");
        if (shell == NULL) {
                fprintf(stderr, "Error eding SHELL env. var.\n");
                return 1;
        }               
       
        /* Overwrite env. var. PATH */
        if (setenv("PATH", "/usr/bin", 1) < 0) {
                fprintf(stderr, "Error setting env. var.\n");
                return 1;
        }
       
        /* Replace this program by a new instance of the shell */
        execl(shell, shell, NULL);
       
        /* We should never get here, so it's an error. */
        fprintf(stderr, "Error starting shell\n");
        return 2;
}

When you run this, the program will exit by starting a new shell that will have the changed PATH. However, the previous shell you started the program from is still running as well. (and the new one will have a different commandline history as well). So if you start the program more than once, there will be a stack of shells running. you can verify this byt running it a few times, and then run:
Code:

/usr/bin/pstree | /bin/grep -B1 pstree
To prevent this, (and keep the same command line history) you need to run the program with "exec", like this:
Code:

exec ./my_program
If you run this a few times,and then check "/usr/bin/pstree | /bin/grep -B1 pstree", there will still be one shell running.

Hope this helps.

Hko 04-21-2004 04:32 PM

P.S. If changing environment variables is the only thing your program does, stick with jim mcnamara's solution. Much easier and more apropriate for just changing env. vars.

itsme86 04-21-2004 11:24 PM

You could just do this: system("VAR=setting; export VAR");

jim mcnamara 04-22-2004 10:58 AM

itsme - wont'work because system() forks (using exec) and creates a subprocess.

"export" only creates the variable for that process and any of it's children - not the parent process.

If a child could alter parent environments by using export, unix would have zero security.

aluser 04-22-2004 06:00 PM

Another way to handle this is to just have your program output shell commands to set the environment the way it wants it. e.g. ssh-agent is meant to be called like "eval `ssh-agent`"

The tricky part of this is that you need to output command appropriate to the shell you're using: csh and sh are a little different. You can check the SHELL environment variable of course.

mvt 04-26-2004 03:39 PM

Thanks for all the replies.

It looks like my original plan is simply not possible.

For closure, I finally used a method like that
proposed by "aluser":
eval `fixpath`
(recall that I am using tcsh)
where the name of my program is: fixpath
and the program writes a string like this to stdout:
set path=(/sbin /usr/bin)

It is not as clean as I had hoped for, but not too ugly.

Thanks 'aluser', for I didn't know about the eval
command.

Mark


All times are GMT -5. The time now is 06:41 PM.