Setting an environment variable through a Perl script [duplicate] - linux

This question already has answers here:
How to Share ENV Variables Among Perl Scripts
(2 answers)
Closed 5 years ago.
I am trying to set an environment variable, LD_LIBRARY_PATH, through a Perl script in the following way:
I have created .profile under /root
.profile has an export command say:
export LD_LIBRARY_PATH=/
My Perl script is test.pl and it has:
#!/usr/bin/perl
system(". /root/.profile");
When I execute ./test.pl, LD_LIBRARY_PATH doesn't change.
What am I doing wrong?

Your current script doesn't even change an environment variable in the Perl script itself. Rather, it invokes a shell as a subprocess; that shell process executes . /root/.profile, which updates $LD_LIBRARY_PATH only in that shell process.
You can change an environment variable in a Perl script (more precisely, in the process running the Perl script) by updating %ENV:
$ENV{LD_LIBRARY_PATH} = '/'; # or some more reasonable value
As perldoc -v %ENV says:
%ENV The hash %ENV contains your current environment. Setting a value in "ENV" changes the environment for any child processes you subsequently "fork()" off.
But that probably still won't do what you want; it won't (and can't) affect the environment of the process that invokes the Perl script (your interactive shell), only the Perl process itself and anything it invokes.
I'll assume you want to update $LD_LIBRARY_PATH in your current interactive shell process. To do that, you can have you Perl script print a shell command that will update $LD_LIBRARY_PATH. Then, rather than simply running your Perl script, you can execute it and then evaluate its output. For example:
$ cat env.pl
#!/usr/bin/perl
use strict;
use warnings;
print "export LD_LIBRARY_PATH=/\n";
$ ./env.pl # just prints the command without executing it
export LD_LIBRARY_PATH=/
$ eval $(./env.pl) # executes the command in the current shell
$ echo $LD_LIBRARY_PATH
/
$
This assumes that your current shell is bash or something similar.
Another option: After modifying %ENV, your Perl script can invoke another command, even a new interactive shell. The new process will inherit its environment from the Perl script. This can be a bit cumbersome, though; for example, if the new process is an interactive shell, it won't inherit unexported variables or history from the parent shell.
(One note, not directly related to your question: The fact that you're messing with /root/.profile implies that you're doing things as root (superuser). This can be dangerous. Use the root account (either by logging into it or via sudo only for things that actually need root privileges. For anything else, use a personal user account.

To change the environment in a Perl script, assign to the %ENV hash:
$ENV{'LD_LIBRARY_PATH'} = '/';
If you want to write a program that's used by a shell to change its environment, the way this is generally done is to have the script write shell commands to stdout. The shell then executes this with command substitution and uses eval to execute the resulting commands:
Perl script:
#!/usr/bin/perl
print 'LD_LIBRARY_PATH=\n';
Shell script:
eval "$(/path/to/perlscript)"
For examples of commands that work like this, see tset and ssh-agent.

system starts a new process, and changing the environment there won't affect the environment in the process of your script (usually—there are generally os-dependent means of changing other processes' environments).
The environment in a perl program is associated with %ENV, which is kind of like (it isn't actually) a tied hash to the environment: changing it will change the environment. Thus:
$ENV{LD_LIBRARY_PATH} = '/';

This can now be done with the Env::Modify module:
use Env::Modify 'source';
source("/root/.profile");
... env settings of .profile are now available to Perl ...

You can't do it.
This is from the Perl FAQ:
In the strictest sense, it can't be done--the script executes as a different process from the shell it was started from. Changes to a process are not reflected in its parent--only in any children created after the change. There is shell magic that may allow you to fake it by eval()ing the script's output in your shell; check out the comp.unix.questions FAQ for details.

Related

How can I write a bash script that sets a variable that's available to the user in the terminal? [duplicate]

This question already has answers here:
Can I export a variable to the environment from a Bash script without sourcing it?
(13 answers)
Closed 3 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
I'm trying to write a shell script that, when run, will set some environment variables that will stay set in the caller's shell.
setenv FOO foo
in csh/tcsh, or
export FOO=foo
in sh/bash only set it during the script's execution.
I already know that
source myscript
will run the commands of the script rather than launching a new shell, and that can result in setting the "caller's" environment.
But here's the rub:
I want this script to be callable from either bash or csh. In other words, I want users of either shell to be able to run my script and have their shell's environment changed. So 'source' won't work for me, since a user running csh can't source a bash script, and a user running bash can't source a csh script.
Is there any reasonable solution that doesn't involve having to write and maintain TWO versions on the script?
Use the "dot space script" calling syntax. For example, here's how to do it using the full path to a script:
. /path/to/set_env_vars.sh
And here's how to do it if you're in the same directory as the script:
. set_env_vars.sh
These execute the script under the current shell instead of loading another one (which is what would happen if you did ./set_env_vars.sh). Because it runs in the same shell, the environmental variables you set will be available when it exits.
This is the same thing as calling source set_env_vars.sh, but it's shorter to type and might work in some places where source doesn't.
Your shell process has a copy of the parent's environment and no access to the parent process's environment whatsoever. When your shell process terminates any changes you've made to its environment are lost. Sourcing a script file is the most commonly used method for configuring a shell environment, you may just want to bite the bullet and maintain one for each of the two flavors of shell.
You're not going to be able to modify the caller's shell because it's in a different process context. When child processes inherit your shell's variables, they're
inheriting copies themselves.
One thing you can do is to write a script that emits the correct commands for tcsh
or sh based how it's invoked. If you're script is "setit" then do:
ln -s setit setit-sh
and
ln -s setit setit-csh
Now either directly or in an alias, you do this from sh
eval `setit-sh`
or this from csh
eval `setit-csh`
setit uses $0 to determine its output style.
This is reminescent of how people use to get the TERM environment variable set.
The advantage here is that setit is just written in whichever shell you like as in:
#!/bin/bash
arg0=$0
arg0=${arg0##*/}
for nv in \
NAME1=VALUE1 \
NAME2=VALUE2
do
if [ x$arg0 = xsetit-sh ]; then
echo 'export '$nv' ;'
elif [ x$arg0 = xsetit-csh ]; then
echo 'setenv '${nv%%=*}' '${nv##*=}' ;'
fi
done
with the symbolic links given above, and the eval of the backquoted expression, this has the desired result.
To simplify invocation for csh, tcsh, or similar shells:
alias dosetit 'eval `setit-csh`'
or for sh, bash, and the like:
alias dosetit='eval `setit-sh`'
One nice thing about this is that you only have to maintain the list in one place.
In theory you could even stick the list in a file and put cat nvpairfilename between "in" and "do".
This is pretty much how login shell terminal settings used to be done: a script would output statments to be executed in the login shell. An alias would generally be used to make invocation simple, as in "tset vt100". As mentioned in another answer, there is also similar functionality in the INN UseNet news server.
In my .bash_profile I have :
# No Proxy
function noproxy
{
/usr/local/sbin/noproxy #turn off proxy server
unset http_proxy HTTP_PROXY https_proxy HTTPs_PROXY
}
# Proxy
function setproxy
{
sh /usr/local/sbin/proxyon #turn on proxy server
http_proxy=http://127.0.0.1:8118/
HTTP_PROXY=$http_proxy
https_proxy=$http_proxy
HTTPS_PROXY=$https_proxy
export http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
}
So when I want to disable the proxy,
the function(s) run in the login shell and sets the variables
as expected and wanted.
It's "kind of" possible through using gdb and setenv(3), although I have a hard time recommending actually doing this. (Additionally, i.e. the most recent ubuntu won't actually let you do this without telling the kernel to be more permissive about ptrace, and the same may go for other distros as well).
$ cat setfoo
#! /bin/bash
gdb /proc/${PPID}/exe ${PPID} <<END >/dev/null
call setenv("foo", "bar", 0)
END
$ echo $foo
$ ./setfoo
$ echo $foo
bar
This works — it isn't what I'd use, but it 'works'. Let's create a script teredo to set the environment variable TEREDO_WORMS:
#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i
It will be interpreted by the Korn shell, exports the environment variable, and then replaces itself with a new interactive shell.
Before running this script, we have SHELL set in the environment to the C shell, and the environment variable TEREDO_WORMS is not set:
% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%
When the script is run, you are in a new shell, another interactive C shell, but the environment variable is set:
% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%
When you exit from this shell, the original shell takes over:
% exit
% env | grep TEREDO
%
The environment variable is not set in the original shell's environment. If you use exec teredo to run the command, then the original interactive shell is replaced by the Korn shell that sets the environment, and then that in turn is replaced by a new interactive C shell:
% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%
If you type exit (or Control-D), then your shell exits, probably logging you out of that window, or taking you back to the previous level of shell from where the experiments started.
The same mechanism works for Bash or Korn shell. You may find that the prompt after the exit commands appears in funny places.
Note the discussion in the comments. This is not a solution I would recommend, but it does achieve the stated purpose of a single script to set the environment that works with all shells (that accept the -i option to make an interactive shell). You could also add "$#" after the option to relay any other arguments, which might then make the shell usable as a general 'set environment and execute command' tool. You might want to omit the -i if there are other arguments, leading to:
#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${#-'-i'}"
The "${#-'-i'}" bit means 'if the argument list contains at least one argument, use the original argument list; otherwise, substitute -i for the non-existent arguments'.
You should use modules, see http://modules.sourceforge.net/
EDIT: The modules package has not been updated since 2012 but still works ok for the basics. All the new features, bells and whistles happen in lmod this day (which I like it more): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod
Another workaround that I don't see mentioned is to write the variable value to a file.
I ran into a very similar issue where I wanted to be able to run the last set test (instead of all my tests). My first plan was to write one command for setting the env variable TESTCASE, and then have another command that would use this to run the test. Needless to say that I had the same exact issue as you did.
But then I came up with this simple hack:
First command ( testset ):
#!/bin/bash
if [ $# -eq 1 ]
then
echo $1 > ~/.TESTCASE
echo "TESTCASE has been set to: $1"
else
echo "Come again?"
fi
Second command (testrun ):
#!/bin/bash
TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE
You can instruct the child process to print its environment variables (by calling "env"), then loop over the printed environment variables in the parent process and call "export" on those variables.
The following code is based on Capturing output of find . -print0 into a bash array
If the parent shell is the bash, you can use
while IFS= read -r -d $'\0' line; do
export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME
If the parent shell is the dash, then read does not provide the -d flag and the code gets more complicated
TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
export VARNAME=something
while IFS= read -r -d $'\0' line; do
echo $(printf '%q' "$line")
done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME
Under OS X bash you can do the following:
Create the bash script file to unset the variable
#!/bin/bash
unset http_proxy
Make the file executable
sudo chmod 744 unsetvar
Create alias
alias unsetvar='source /your/path/to/the/script/unsetvar'
It should be ready to use so long you have the folder containing your script file appended to the path.
It's not what I would call outstanding, but this also works if you need to call the script from the shell anyway. It's not a good solution, but for a single static environment variable, it works well enough.
1.) Create a script with a condition that exits either 0 (Successful) or 1 (Not successful)
if [[ $foo == "True" ]]; then
exit 0
else
exit 1
2.) Create an alias that is dependent on the exit code.
alias='myscript.sh && export MyVariable'
You call the alias, which calls the script, which evaluates the condition, which is required to exit zero via the '&&' in order to set the environment variable in the parent shell.
This is flotsam, but it can be useful in a pinch.
You can invoke another one Bash with the different bash_profile.
Also, you can create special bash_profile for using in multi-bashprofile environment.
Remember that you can use functions inside of bashprofile, and that functions will be avialable globally.
for example, "function user { export USER_NAME $1 }" can set variable in runtime, for example: user olegchir && env | grep olegchir
Another option is to use "Environment Modules" (http://modules.sourceforge.net/). This unfortunately introduces a third language into the mix. You define the environment with the language of Tcl, but there are a few handy commands for typical modifications (prepend vs. append vs set). You will also need to have environment modules installed. You can then use module load *XXX* to name the environment you want. The module command is basically a fancy alias for the eval mechanism described above by Thomas Kammeyer. The main advantage here is that you can maintain the environment in one language and rely on "Environment Modules" to translate it to sh, ksh, bash, csh, tcsh, zsh, python (?!?!!), etc.
I created a solution using pipes, eval and signal.
parent() {
if [ -z "$G_EVAL_FD" ]; then
die 1 "Rode primeiro parent_setup no processo pai"
fi
if [ $(ppid) = "$$" ]; then
"$#"
else
kill -SIGUSR1 $$
echo "$#">&$G_EVAL_FD
fi
}
parent_setup() {
G_EVAL_FD=99
tempfile=$(mktemp -u)
mkfifo "$tempfile"
eval "exec $G_EVAL_FD<>'$tempfile'"
rm -f "$tempfile"
trap "read CMD <&$G_EVAL_FD; eval \"\$CMD\"" USR1
}
parent_setup #on parent shell context
( A=1 ); echo $A # prints nothing
( parent A=1 ); echo $A # prints 1
It might work with any command.
I don't see any answer documenting how to work around this problem with cooperating processes. A common pattern with things like ssh-agent is to have the child process print an expression which the parent can eval.
bash$ eval $(shh-agent)
For example, ssh-agent has options to select Csh or Bourne-compatible output syntax.
bash$ ssh-agent
SSH2_AUTH_SOCK=/tmp/ssh-era/ssh2-10690-agent; export SSH2_AUTH_SOCK;
SSH2_AGENT_PID=10691; export SSH2_AGENT_PID;
echo Agent pid 10691;
(This causes the agent to start running, but doesn't allow you to actually use it, unless you now copy-paste this output to your shell prompt.) Compare:
bash$ ssh-agent -c
setenv SSH2_AUTH_SOCK /tmp/ssh-era/ssh2-10751-agent;
setenv SSH2_AGENT_PID 10752;
echo Agent pid 10752;
(As you can see, csh and tcsh uses setenv to set varibles.)
Your own program can do this, too.
bash$ foo=$(makefoo)
Your makefoo script would simply calculate and print the value, and let the caller do whatever they want with it -- assigning it to a variable is a common use case, but probably not something you want to hard-code into the tool which produces the value.
Technically, that is correct -- only 'eval' doesn't fork another shell. However, from the point of view of the application you're trying to run in the modified environment, the difference is nil: the child inherits the environment of its parent, so the (modified) environment is conveyed to all descending processes.
Ipso facto, the changed environment variable 'sticks' -- as long as you are running under the parent program/shell.
If it is absolutely necessary for the environment variable to remain after the parent (Perl or shell) has exited, it is necessary for the parent shell to do the heavy lifting. One method I've seen in the documentation is for the current script to spawn an executable file with the necessary 'export' language, and then trick the parent shell into executing it -- always being cognizant of the fact that you need to preface the command with 'source' if you're trying to leave a non-volatile version of the modified environment behind. A Kluge at best.
The second method is to modify the script that initiates the shell environment (.bashrc or whatever) to contain the modified parameter. This can be dangerous -- if you hose up the initialization script it may make your shell unavailable the next time it tries to launch. There are plenty of tools for modifying the current shell; by affixing the necessary tweaks to the 'launcher' you effectively push those changes forward as well.
Generally not a good idea; if you only need the environment changes for a particular application suite, you'll have to go back and return the shell launch script to its pristine state (using vi or whatever) afterwards.
In short, there are no good (and easy) methods. Presumably this was made difficult to ensure the security of the system was not irrevocably compromised.
The short answer is no, you cannot alter the environment of the parent process, but it seems like what you want is an environment with custom environment variables and the shell that the user has chosen.
So why not simply something like
#!/usr/bin/env bash
FOO=foo $SHELL
Then when you are done with the environment, just exit.
You could always use aliases
alias your_env='source ~/scripts/your_env.sh'
I did this many years ago. If I rememeber correctly, I included an alias in each of .bashrc and .cshrc, with parameters, aliasing the respective forms of setting the environment to a common form.
Then the script that you will source in any of the two shells has a command with that last form, that is suitable aliased in each shell.
If I find the concrete aliases, I will post them.
Other than writings conditionals depending on what $SHELL/$TERM is set to, no. What's wrong with using Perl? It's pretty ubiquitous (I can't think of a single UNIX variant that doesn't have it), and it'll spare you the trouble.

Perl script, how to source an environment variables from .bash_profile

I need some quick advice on perl script. I created a script that basically calls other perl scripts and many other shell scripts within those. The problem I'm facing, is simply trying to make this run on a universal level by setting one environment variable.
This is on linux RHEL/CentOS by the way...
so I add my variables to .bash_profile and it works without an issue if I MANUALLY source the file first, then run my perl script! This is, OK, but I would like the script to automate this part instead of needing the extra, manual sourcing step.
So my script looks like this... in short
#!/usr/bin/perl
use warnings;
use strict;
`/bin/bash ~/.bash_profile`;
blah blah blah more code etc;
When launching the main script (where this part of the code is) it works no problem. It's all the subsequent calls made to other scripts that are failing...as if it is not passing the variable on to the rest of the scripts.
Any ideas??
Thanks,
The easiest way would be to set the environment variables within perl with $ENV{"name"}=.... These variables then will be propagated automatically to any programs started from within the perl script, no matter if perl or shell scripts
alternatively you could open the .bash_profile, parse it within perl, extract the variables and then set them again within perl with $ENV. This is error prone because there might be several ways to declare the variables.
or you could spawn a shell, which reads the .bash_profile and calls env afterwards. Then you read and parse the output from this shell. This is similar to the previous proposal, but the output you have to parse is more clearly defined.
or you could use a shell script which sources .bash_profile and then spawns the perl script.
Environment variables are inherited by child processes from their parent, so you simply need to launch perl from a shell that sourced ~/.bash_profile.
bash login shells source that file automatically, so it's just a question of setting bash as your login shell. You could also use bash -l.
bash -lc 'exec script.pl args'
If you can't setup the correct environment before launching Perl, you can bootstrap a bash login shell.
if (#ARGV && $ARGV[0] eq 'setup') {
shift(#ARGV);
} else {
exec('bash', '-lc', 'exec "$#"', '-', $^X, $0, 'setup', #ARGV) or die $!;
}
In all three cases, the variable is accessed using
$ENV{VAR_NAME}
Backticks (and system, and open, etc.) spawns a separate process that inherits the environment from your Perl program, but can only affect its own environment, not propogate changes back to your Perl script.
Shell::GetEnv has a few tricks that will help you incorporate those changes to the child environment, but often times you will find it is easier to parse .bash_profile yourself.
The more recent Env::Modify module can handle this task, leveraging the tricks in Shell::GetEnv.
use Env::Modify 'source';
source("$ENV{HOME}/.bash_profile");
using $ENV we can get any value from .profile/.bash_profile
Example:
suppose any variable is store in your .profile/.bash_profile
export CONNECT="Connection"
Retrieve the same variable in your perl scripts from .profile/.bash_profile as:
my $DB_CONNECT = $ENV{CONNECT};

How to run a csh script from a sh script

I was wondering if there is a way to source a csh script from a sh script. Below is an example of what is trying to be implemented:
script1.sh:
#!/bin/sh
source script2
script2:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
When I run sh script1.sh, I get syntax errors generated from script2 (expected since we are using a different Shebang). Is there a way I can run script2 through script1?
Instead of source script2 run it as:
csh -f script2
Since your use case depends on retaining environment variables set by the csh script, try adding this to the beginning of script1:
#!/bin/sh
if [ "$csh_executed" -ne 1 ]; then
csh_executed=1 exec csh -c "source script2;
exec /bin/sh \"$0\" \"\$argv\"" "$#"
fi
# rest of script1
If the csh_executed variable is not set to 1 in the environment, run a csh script that sources script2 then executes an instance of sh, which will retain the changes to the environment made in script2. exec is used to avoid creating new processes for each shell instance, instead just "switching" from one shell to the next. Setting csh_executed in the environment of the csh command ensures that we don't get stuck in a loop when script1 is re-executed by the csh instance.
Unfortunately, there is one drawback that I don't think can be fixed, at least not with my limited knowledge of csh: the second invocation of script1 receives all the original arguments as a single string, rather than a sequence of distinct arguments.
You don't want source there; it runs the given script inside your existing shell, without spawning a subprocess. Obviously, your sh process can't run something like that which isn't a sh script.
Just call the script directly, assuming it is executable:
script2
The closest you can come to sourcing a script with a different executor than your original script is to use exec. exec will replace the running process space with the new process. Unlike source, however, when your exec-ed program ends, the entire process ends. So you can do this:
#!/bin/sh
exec /path/to/csh/script
but you can't do this:
#!/bin/sh
exec /path/to/csh/script
some-other-command
However, are you sure you really want to source the script? Maybe you just want to run it in a subprocess:
#!/bin/sh
csh -f /path/to/csh/script
some-other-command
You want the settings in your csh script to apply to the sh script that invokes it.
Basically, you can't do that, though there are some (rather ugly) ways you could make it work. If you execute your csh script, it will set those variables in the context of the process running the script; they'll vanish as soon as it returns to the caller.
Your best bet is simply to write a new version of your csh script as an sh script, and source or . it from the calling sh script.
You could translate your csh script:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
to this:
export TEST=1234
export PATH=/home/user/sandbox
(csh treats the shell array variable $path specially, tying it to the environment variable $PATH. sh and its derivatives don't do that, they deal with $PATH itself directly.)
Note that a script intended to be sourced should not have a #! line at the top, since it doesn't make sense to execute it in its own process; you need to execute its contents in the context of the caller.
If maintaining two copies of the script, one to be sourced from csh or tcsh scripts and another to be sourced or .ed from sh/ksh/bash/zsh script, is not practical, there are other solutions. For example, your script can print a series of sh commands to be executed; you can then do something like
eval `./foo.csh`
(line endings will pose some issues here).
Or you can modify the csh script so it sets the required environment variables and then invokes some specified command, which could be a new interactive shell; this is inconvenient, since it doesn't set those variables in the interactive shell you're running.
If a software package requires some special environment variables to be set, it's common practice to provide scripts called, for example, setup.sh and setup.csh, so that sh/ksh/bash/zsh users can do:
. /path/to/package/setup.sh
and csh/tcsh users can do:
source /path/to/package/setup.csh
Incidentally, this command:
set path = /home/user/sandbox
in your sample script is probably not a good idea. It replaces your entire $PATH with just a single directory, which means you won't be able to execute simple commands like ls unless you specify their full paths. You'd usually want something like:
set path = ( $path /home/user/sandbox )
or, in sh:
PATH=$PATH:/home/user/sandbox

Setting Enviroment Variables Dynamically on Linux

I am currently looking for a way to set enviroment variables in Linux via a simple shell script. Within the script I am currently using the 'export' command, however this only has scope within the script where system-wide scope is needed.
Is there anyway I can do this via a shell script, or will another method need to be used?
When you run a shell script, it executes in a sub-shell. What you need is to execute it in the context of the current shell, by sourcing it with:
source myshell.sh
or:
. myshell.sh
The latter is my preferred approach since I'm inherently lazy.
If you're talking about system-wide scope inasmuch as you want to affect everybody, you'll need to put your commands in a place where they're sourced at login time (or shell creation time), /etc/profile for example. Where you put your commands depends on the shell being used.
You can find out what scripts get executed by examining the man page for your shell:
man bash
The bash shell, when invoked as a login shell (including as a non-login shell but with the --login parameter), will use /etc/profile and the first of ~/.bash_profile, ~/.bash_login or ~/.profile.
Non-login bash shells will use. unless invoked with --norc or --rcfile <filename>, the files /etc/bash.bashrc and ~/.bashrc.
I'm pretty certain it's even more convoluted than that depending on how the shell is run, but that's as far as my memory stretches. The man page should detail it all.
You could have your script check for the existence of something like /var/myprog/env-vars-to-load and 'source' it then unlink it if it exists, perhaps using trap and a signal. Its hard to say, I'm not familiar with your program.
There is no way to 'inject' environmental variables into another process' address space, so you'll have to find some method of IPC which will can instruct the process on what to set.
A fundamental aspect of environment variables is that you cannot affect the environment for any process but your own and child processes that you spawn. You can't create a script that sets "system wide" environment variables that somehow become usable by other processes.
On the shell prompt:
$ source script.sh
And set the env vars in script.sh
test.sh
#!/bin/bash
echo "export MY_VAR=STACK_OVERFLOW" >> $HOME/.bashrc
. $HOME/.bashrc
sh task.sh
task.sh
#!/bin/sh
echo $MY_VAR
Add executable rights:
chmod +x test.sh task.sh
And lauch test.sh
./test.sh
Result:
STACK_OVERFLOW

How do I import environment settings into my Perl program?

I have a script whose content simply exports a variable in linux.
export LD_LIBRARY_PATH=....
I want to run this script in my Perl script so whoever is running my Perl script will have their LD_LIBRARY_PATH set. Can i just do this in the beginning of my Perl script:
#!/usr/bin/perl -w
system(". /myfolder1/myfolder2/myScript.sh");
#!/bin/sh
. /myfolder1/myfolder2/myScript.sh
exec perl -wxS "$0" "$#"
#!/usr/bin/perl -w
# .. the rest of your script as normal
When you run this, it will first be executed by /bin/sh, which is capable of loading myScript.sh into the local environment. sh then execs Perl, which is told to continue from the following line.
This won't work. To change the environment inside your Perl script (and to change the environment that will be passed on to commands run from inside your Perl script), change the %ENV variable.
$ENV{"LD_LIBRARY_PATH"} = ... ;
This won't work. There is no way for a subshell to manipulate the environment of the parent process.
But you could make your script echo the string you want to set as LD_LIBRARY_PATH and then from within your Perl script you could do something like that:
$ENV{LD_LIBRARY_PATH} = `path/to/your/script.sh`;
Of course, a bit of error checking might also be a good idea.
No. Your environment changes made in a child cannot affect the parent. This means running a script will not affect perl. Also perl will not affect the shell from which it was called. You can edit the environment inside perl by changing the special variable %ENV. If there's some kind of unreproducible calculation done in that script, maybe the script should just echo the setting and perl can pick that up on STDOUT and use it.
I {changed directory, modified my environment} in a perl script. How come the change disappeared when I exited the script? How do I get my changes to be visible?
Unix In the strictest sense, it can't be done -- the script executes
as a different process from the shell
it was started from. Changes to a
process are not reflected in its
parent, only in its own children
created after the change.
I had a similar problem a few years ago and whipped up a little module, Env::Sourced, that should do the trick.
use Env::Sourced qw(/myfolder1/myfolder2/myScript.sh);
...
Another option (other than making the changes directly in Perl's %ENV) is to make the changes you want a Perl module, so that you can say:
use MyEnvironment;
and have it modify your environment in all your scripts. It would make it simple to make changes after the fact that will not require editing every script.
The module itself will be simple, something like this:
package MyEnvironment;
$ENV{LD_LIBRARY_PATH} .= ":/some/path/you/want/appended";
# Any other changes you want here.
1;
That won't work. An (unpleasant) alternative might be to replace /usr/bin/perl with a shell script that first executes your script and then executes the perl executable.
This can't be done in the way you're trying to do this.
It either needs a wrapper shell script that sets LD_LIBRARY_PATH and then calls your perl script, or any user executing the script needs to have LD_LIBRARY_PATH set correctly in the first place.
If doing the latter, then this can be managed globally by editing /etc/profile and /etc/cshrc (for ksh, sh, bash, csh and tcsh) shells. You can then test for the value of LD_LIBRARY_PATH in your script and if not set/set incorrectly then print a friendly message to the user. Alternatively individual users can set this in their local .profile/.cshrc files.
Note: you haven't given any information about the environment or useres that might run this, so there's also the possibility that users may set LD_LIBRARY_PATH to something they need. If you do check LD_LIBRARY_PATH for a "good" value in your script, then keep in mind that several paths may have been specified, so you will need to parse this environment variable properly.
If you can find the right place in your perl script, this works as in my example:
$ENV{"LD_LIBRARY_PATH"} = "/oracle/product/10g/lib";
And it didn't require me to call another script to set the env var.
The Env::Modify module addresses this issue, at least for POSIX-y platforms:
use Env::Modify 'source';
source("/myfolder1/myfolder2/myScript.sh");
... environment settings from myScript.sh are now available to Perl ...

Resources