7

I am trying to set environment variable using Perl. It should export this variable outside (in current shell) not just in the script.

I tried:

`setenv X1 /p/fsd`

system("setenv X1 /p/fsd") == 0 or die "failed:$?"

system command "setenv X1 /p/fsd" failed: -1

$ENV{"X1"} = "/p/fsd"; 

Nothing seems to be working.

If it matters i am using TCSH.

user1793023
  • 117
  • 1
  • 2
  • 6
  • Possible duplicate of [Setting an environment variable through a Perl script](http://stackoverflow.com/questions/19192682/setting-an-environment-variable-through-a-perl-script) – imz -- Ivan Zakharyaschev Nov 30 '15 at 09:33

4 Answers4

14
$ENV{"X1"} = "/p/fsd"; 

is the right way.

Test in perlconsole :

Perl> $ENV{X1} = "/p/fsd";
/p/fsd

Perl> system('echo $X1');
/p/fsd
0

NOTE

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • This will only work while script is running, right? Once script stops they are gone. What i am trying to do is i have 10-15 environment variable in the SHELL and they update frequently. So instead of me setting them manually.. i was thinking to script it. – user1793023 Nov 15 '12 at 00:29
  • This is the principle of the subshell. If you kill the father, you kill the son too, this is sad, but this is life. – Gilles Quénot Nov 15 '12 at 00:31
  • Added link for explanations about subshells and parents. – Gilles Quénot Nov 15 '12 at 00:36
  • yeah.. in that case i might have to change shell and use Bash and try to script using shell scripting since tcsh is brain dead for scripting. – user1793023 Nov 15 '12 at 00:42
  • Thanks... for opening my eyes... :) i thought there has to be a way but doesn't look like using perl.... – user1793023 Nov 15 '12 at 00:43
7

Equally important to know how to set an env variable is how to delete it:

delete $ENV{"X1"};

This will delete the environment variable for the perl process and any children processes. But the environment variable will still be set for the parent process.

jcarballo
  • 27,395
  • 3
  • 28
  • 28
  • Should it be *"X1"* or *X1*? – Peter Mortensen Oct 10 '14 at 10:07
  • 1
    @PeterMortensen Those are equivalent. In general, we leave out the quotes because it is simpler. Especially with environment variables because they are all caps and no special characters. It is possible that quotes are necessary if you are using weird special characters. See [this discussion](http://stackoverflow.com/questions/401556/are-quotes-around-hash-keys-a-good-practice-in-perl) – mareoraft Nov 15 '14 at 14:19
3

Because there's no special characters in setenv X1 /p/fsd,

system("setenv X1 /p/fsd")

is equivalent to

system("setenv", "X1", "/p/fsd")

It's failing because there's is no program named setenv. If this optimisation didn't exist, you get a different result*. In that case,

system("setenv X1 /p/fsd")

would be equivalent to

system("sh", "-c", "setenv X1 /p/fsd")

That wouldn't work either because sh has no setenv command. So you could run the following instead:

system("tcsh", "-c", "setenv X1 /p/fsd")

But it would be pointless. You'd create a shell, set one of its variables. Then the shell exits and its variables cease to exist.

If you want to set a env var seen by Perl and its children, simply use

$ENV{X1} = "/p/fsd";         # Until end of program

or

local $ENV{X1} = "/p/fsd";   # Until end of scope

* — Optimised code shouldn't behave differently than unoptimised code, but since the optimisation just changes what error you get, it's acceptable.

ikegami
  • 367,544
  • 15
  • 269
  • 518
1

As other replies have mentioned, you can't set an environment variable in the parent from the child. However, you could do something complicated in perl and then pass the end result back to the shell to be set. For example, in tcsh:

eval `perl -le 'print q(setenv X1 /p/fsd)'`

You could make this feel a bit more transparent with, e.g.,

alias x1.pl 'eval `x1.pl`'
mavit
  • 619
  • 6
  • 13
  • `ssh-agent` has the same problem (setting environment variables in the calling shell) and uses the same `eval` trick. It has even switches for the different setenv syntaxes in `sh` and `csh` (`-s` resp. `-c`). – Slaven Rezic Nov 15 '13 at 08:09