Setting environment variables from a Perl script

J

J. Romano

Dear Perl community,

In the past I have tried to find an answer to the question of how
to set environment variables in Perl scripts and make them last even
after the Perl script has finished. I eventually found the response
mentioned in "perldoc -q environment", which basically says that it
can't be done (although there are work-arounds if you're willing to
use a few Unix tricks).

However, I just recently discovered an easy way to do it. It works
like a charm in Unix. (But unfortunately, it doesn't work so great on
Win32.)

Basically, you write your script as normal, setting environment
variables, changing them, deleting them, and even changing
directories:

$ENV{EDITOR} = "/usr/bin/vi"; # make vi default editor
$ENV{PATH} .= ":/usr/bin/games"; # add games dir to path
delete $ENV{PAGER}; # remove the pager environment variable
chdir($ENV{HOME} . "/bin") or warn $!; # change to my bin dir

But at the end of the script, add this line:

exec $ENV{SHELL};

Run your script, and voila'! The environment variable changes stick!

I've found it's best to run your script with "exec" in front of it,
like so:

exec perl script.pl

otherwise, you'll have to type an extra "exit" for every time you run
the script in order to fully exit the shell.

Of course, this script assumes that your SHELL environment variable
exists and that it's set to your current shell.

In DOS using ActiveState Perl, I've found that changing:

exec $ENV{SHELL};

to:

system 'cmd';

works better than changing it to:

exec 'cmd';

(I have a hunch that ActivePerl implements the exec() call by
replacing it with system() and exit(), but I don't know for sure...)

As far as I know, in DOS you can't run the exec command, so you'll
have to type an extra "exit" to close down the DOS terminal window.
And deleting an evironment variable doesn't seem to work, either (at
least, not when I tried it). No error is generated; it just doesn't
appear to work.

So this approach doesn't fare so well in Win32 DOS, but it looks to
me that it works great in Unix. This goes against what the perldoc
says, so if anybody knows a caveat about using this technique (on
Unix) that I don't see, please speak up. But if there are no
problems, then I would think that this popular dilemma has been
solved.

Happy Perling!

-- Jean-Luc
 
A

A. Sinan Unur

(e-mail address removed) (J. Romano) wrote in
Dear Perl community,

In the past I have tried to find an answer to the question of how
to set environment variables in Perl scripts and make them last even
after the Perl script has finished. I eventually found the response
mentioned in "perldoc -q environment", which basically says that it
can't be done (although there are work-arounds if you're willing to
use a few Unix tricks).
....

But at the end of the script, add this line:

exec $ENV{SHELL};

Run your script, and voila'! The environment variable changes stick!
....

This goes against what the perldoc says, so if anybody knows a
caveat about using this technique (on Unix) that I don't see,
please speak up. But if there are no problems, then I would
think that this popular dilemma has been solved.

Happy Perling!

-- Jean-Luc

Jean-Luc:

This complete and utter nonsense: You have not changed the environment
variables in the shell from which you started your program. Instead, you
started a new shell with a new environment. That may be what you want but
then it very well may not be. The answer to the FAQ stands.
 
J

J. Romano

(e-mail address removed) (J. Romano) wrote in
A. Sinan Unur said:
This complete and utter nonsense: You have not changed the environment
variables in the shell from which you started your program. Instead, you
started a new shell with a new environment. That may be what you want but
then it very well may not be. The answer to the FAQ stands.


Be careful what you call "complete and utter nonsense": The
perldoc explicitly says that "there is shell magic that may allow you
to fake it by eval()ing the script's output in your shell." That
solution probably suffers the same faults my solution has.
Nevertheless, it made it into the perldocs. (And if it doesn't happen
to have the same faults that render my own findings "complete and
utter nonsense", I'd be happy to see that solution.)

Of course, the changes made by my solution aren't permanent (in
that, once you exit your shell and restart it, the changes made by the
Perl script are no longer there), but there are times when a user
needs to set up the ideal environment in which to begin work on a
specific task (I've done it several times myself), but doesn't want
those environment changes to be permanent.

That scenario is what leads many Perl users to ask the question, "I
know how to change environment variables in Perl, but how do I made
them outlast my Perl program?" Mine is one such solution that doesn't
require "...shell magic that may allow you to fake it by eval()ing the
script's output in your shell." Not that there's anything wrong with
that; I just offer a different solution.

-- Jean-Luc
 
K

Keith Keller

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Of course, the changes made by my solution aren't permanent (in
that, once you exit your shell and restart it, the changes made by the
Perl script are no longer there), but there are times when a user
needs to set up the ideal environment in which to begin work on a
specific task (I've done it several times myself), but doesn't want
those environment changes to be permanent.

Don't you think it's a bit overkill to use a Perl script to set
shell environment variables? Why not (for example) write a bash
script that accomplishes the same task?

- --keith

- --
(e-mail address removed)-francisco.ca.us
(try just my userid to email me)
AOLSFAQ=http://wombat.san-francisco.ca.us/cgi-bin/fom

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQFA4YZ5hVcNCxZ5ID8RAtubAKCVvzdTr2DBNYgkXI8ppGE5Cx+C3QCfXanq
j/xx/NsHf+etsB8ltzdF9pI=
=nqs1
-----END PGP SIGNATURE-----
 
J

J. Romano

Keith Keller said:
Don't you think it's a bit overkill to use a Perl script to set
shell environment variables?

That's a good question. I'll begin by saying that I used to write
shell scripts to do just that before I took the time to learn Perl. I
was able to write fairly elaborate scripts, but it was very
frustrating at times: between bash, csh, and ksh, I couldn't always
keep all the dialectual differences straight to the point that I had
trouble remembering how to do a simple loop or even a simple
assignment. In some cases, the shell language I started with lacked a
feature that another shell had, so I had to re-write my script from
scratch using the other shell language.

That's one of the reasons I liked Perl so much when I started
learning it. It had a superset of the shells' features in a syntax
that made sense to a C programmer.
Why not (for example) write a bash script that accomplishes
the same task?

Because the Perl script is much easier to write and understand.
I'll give you an example:

Back when I was a student in college, as part of our homework
assignments, we had to run a specific program the Unix machines. Many
times these programs required that certain environment variables were
set and, as a result, the instructors very often provided us with a
file for us to "source", like with the following command:

source cs400

That would set our environment variables (and maybe even change our
working directories). One of the environment variables that always
got modified was $PATH. As a result, my $PATH became super-huge, and
many of its entries were duplicates, making it difficult to
troubleshoot Unix problems as the $PATH was very convoluted.

I did not know Perl at the time, so I used csh to write myself a
script to simplify my $PATH. It worked, but it was not easy. Once I
had written the script, I could run a line like:

source simplifyPath

and duplicates would automatically be removed from my $PATH.

I don't remember how I wrote it, but I do remember that it was more
than five lines of code. And here's where Perl comes in: With this
Perl script that is effectively four lines long, I achieve the same
effect:


#!/usr/bin/perl -w
# File: simplifyPath.pl
use strict;
my %seen; # store paths already seen

my @pathList = split /:/, $ENV{PATH};
@pathList = grep { ! $seen{$_}++ } @pathList;
$ENV{PATH} = join ':', @pathList;

exec $ENV{SHELL};
__END__


Now, instead of typing "source simplifyPath", I type:

exec simplifyPath.pl

and I get a new $PATH that has all the duplicate paths removed.

Could I have done it with a bash script? Definitely. Like I said,
I've done it before with csh, but setting my environment variables and
my current directory with Perl gives me all the power of the Perl
programming language.

And this "Perl power" is why, periodically, we get users asking how
to use Perl to set environment variables that outlast the Perl script.
Unfortunately, most of them receive the answer that "it can't be
done." And that's the reason behind my posts -- to show that it CAN
be done.

I hope this answers your questions, Keith.

-- Jean-Luc
 
D

Darren Dunham

J. Romano said:
So this approach doesn't fare so well in Win32 DOS, but it looks to
me that it works great in Unix. This goes against what the perldoc
says, so if anybody knows a caveat about using this technique (on
Unix) that I don't see, please speak up. But if there are no
problems, then I would think that this popular dilemma has been
solved.

This isn't the same shell, but a new one. As a result, any shell
variables you may have set in the session will be lost.

$ BAR="bar bar"
$ echo "$FOO - $BAR"
- bar bar
$ exec /tmp/perl
execing /usr/bin/bash
$ echo "$FOO - $BAR"
foo foo -
$

Depending on your shell, you may lose history (although many will use a
..history file which will maintain state). You'd certainly lose any
connections to associated jobs.

$ sleep 500 &
[1] 2255
$ jobs
[1]+ Running sleep 500 &
$ exec /tmp/perl
execing /usr/bin/bash
$ jobs
$

I wouldn't call the issue "solved" by this technique. It's another
option.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top