6

This shell script

#!/bin/csh
set VAR=12345
echo $VAR

will peacefully give the output 12345 at shell. I need to use C++ to do the same in some part of the code:

string str = "12345";
retValue="set var1= "+str;      
system(retValue1.c_str());
system("echo $var1");

This doesn't create a system variable var1 and echos null which is understandable as each system function would create a child process with different environment variables. So I combine them as follows using just one system function...but it echos null again.

retValue="set var1= "+str;
retValue1=retValue+";\n echo $var1";
system(retValue1.c_str());

Can someone please guide me to set up the system variable thru C++. Thanks a lot in advance!

Matvey Aksenov
  • 3,802
  • 3
  • 23
  • 45
Ankita Sharma
  • 69
  • 1
  • 1
  • 3

6 Answers6

15

Look at setenv in <cstdlib>:

#include <cstdlib>

setenv("VAR", "12345", true);
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 3
    +1 for using the correct function. Several other answers recommend putenv, but putenv *should not be used*. setenv is a much better interface. In particular, putenv( var ) where var is an automatic variable will often have unexpected behavior. – William Pursell Nov 23 '11 at 14:23
  • @WilliamPursell Can you elaborate why not putenv()? Just curious – user997112 Jun 02 '20 at 17:06
  • 1
    The man page says it best: `The string pointed to by string becomes part of the environment. A program should not alter or free the string, and should not use stack or other transient string variables as arguments to putenv(). The setenv() function is strongly preferred to putenv().` – William Pursell Jun 02 '20 at 17:10
1

You can use putenv().

#include <cstdlib>
...
putenv("VAR=12345");

This is very convenient, but the string is not copied by putenv. This means that if you modify it later, then you modify the environment. That's not an issue for a literal, but the way you are forming your strings, using std::string is not readily compatible with putenv().

The alternative then is to use setenv()

#include <cstdlib>
...
setenv("VAR", "12345", true);

With setenv(), copies of the input are made and you are safe to dispose of the strings after calling setenv().

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Good, I'm glad to hear it. Please remember to accept one of the answers. Your choice as to which one. – David Heffernan Nov 23 '11 at 14:19
  • 1
    +1: In particular, if you invoke putenv( v ) where v is an automatic variable and then return from the function, the environment is borked. Do not use putenv. Always use setenv. – William Pursell Nov 23 '11 at 14:25
1

You basically can't do that.

You could call putenv to change environment variables in your own process and in all future children processes, but there is no way (and this is good) to change the environment of the parent shell process.

You could have a use convention for your C++ program that e.g. it is outputting some shell commands to be sourced (or eval-ed) by the user. An example of this is ssh-agent -s.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • The original poster's example is a `system("set X=foo")` which don't work as he expects.... I'm surprised of the downvote and of the other answers. There is no way a Linux program can forcibly change the environment of the parent shell (if any). – Basile Starynkevitch Nov 23 '11 at 14:13
  • Are you 100% sure that the poster wants to do that? Would be odd to want to write a C++ program to replicate what `set` does from the shell. Perhaps the problem is that `system("set X=Y")` starts another process and so the change is lost when it ends. Perhaps the poster actually wants to change the environment of the current process. BTW, I'm not your downvoter. – David Heffernan Nov 23 '11 at 14:18
  • In fact poster's comment to my answer seems to confirm my suspicions, but I do think there's a lot of scope for confusion here!! – David Heffernan Nov 23 '11 at 14:19
0

Note that the otherwise excellent CPPreference site does not seem to mention setenv among the functions available in the <cstdlib> header, only getenv. This may not be a problem though as I could use setenv by #include-ing <cstdlib> on a Centos 7 system with GCC 9.1. I suspect in most cases <cstdlib> is just a thin wrapper around <stdlib.h>.

Another small thing to note is that setenv takes C-style character arguments (also for the value of the environment variable to be set). If you use C++ strings (as you should), don't forget to convert them using their .c_str() method.

András Aszódi
  • 8,948
  • 5
  • 48
  • 51
0

The function you want is probably putenv(). You didn't specify which OS you are on, so I'll assume Linux because that's the man page I have handy:

int putenv(char *string);

The putenv() function adds or changes the value of environment variables. The argument string is of the form name=value. If name does not already exist in the environment, then string is added to the environment. If name does exist, then the value of name in the environment is changed to value. The string pointed to by string becomes part of the environment, so altering the string changes the environment.

IIRC, there is a putenv on win32 as well. Finally you might try looking at this question, possibly a dup

Community
  • 1
  • 1
kbyrd
  • 3,321
  • 27
  • 41
0

Above answers explains correctly as to how to set environment variable from a C++ program which is basically setenv()

The only other point i wanted to make is that why your approach doesn't work? The reason is, that when a process is loaded, the system command is loaded with new context - an equivalent of a new shell. Actually your environment variable is getting set but when you comeback it is lost.

Refer to this http://pubs.opengroup.org/onlinepubs/007904975/functions/setenv.html.

Infact, the setenv() sets the env variables of parent process! Which is why it works for you.

Dipan Mehta
  • 2,110
  • 1
  • 17
  • 31