Can we set a variable used in a Perl script as environment variable? - linux

I have a Perl script which has a variable like my $name. Can we set the contents of $name as an environment variable which we can import and use in other files?
I tried like $ENV{NAME}=name, but this is not working.

If you want to affect the environment of your process or your child processes, just use the %ENV hash:
$ENV{CVSROOT}='<cvs>';
If you want to affect the environment of your parent process, you can't. At least not without cooperation of the parent process. The standard process is to emit a shell script and have the parent process execute that shell script:
#!/usr/bin/perl -w
print 'export CVSROOT=<cvs>';
... and call that script from the shell (script) as:
eval `myscript.pl`

Environment variables are specific to a process. When a child process is spawned, it inherits copies of its parent's environment variables, but any changes it makes to them are restricted to itself and any children it spawns after the change.
So no, you can't set an environment variable for your shell from within a script you run.

Related

When running a bash script within another script, are all variables defined in the parent script inherited to the child?

For example, say I have script1.sh and I need to call script2.sh. Will script2.sh be able to use any variables defined script1.sh? If yes, if I went a step deeper and called script3.sh within script2.sh, would that have access to script1.sh variables?
If not, what would have to be done to achieve that?
There are three ways a variable may be made available for use by a script launched by another script :
Marking the variable for export (such as with the export keyword used at the time of declaration or afterwards, or by using the -x option of declare, local or typeset) ;
Putting an assignment for the variable as a prefix to the command being executed (e.g. varname=1 command and args), separated by spaces only ;
Calling the child script with source or ., which causes the script to be read and interpreted by the current shell instead of being launched as a separate process, and therefore makes all variables of the current context (including local variables) available to the child script.
Note that marking a variable for export will cause this variable to be copied to the memory space of the child process, and this copy then becomes independent from the variable of the parent shell : modifying it in the child will not change the value in the parent.
Using source or . is the only way you can cause a child script to modify variables in the parent script, as a child process never has access to the memory space of its parent.
Only the exported variables are accessible in the called script:
1.sh
#! /bin/bash
export exported=1
not_exported=2
2.sh
2.sh
#! /bin/bash
echo $exported
echo $not_exported
Running 1.sh only outputs 1.
You can export a variable only for a dingle call by assigning to it before the call:
not_exported=3 2.sh

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};

incrementing an environmental variable

I need to increment an environmental variable by these steps:
envar=1
export envar
sh script_incrementation
echo $envar
where script_incrementation contains something like this:
#! /bin/sh
envar=$[envar+1] #I've tried also other methods of incrementation
export envar
Whatever I do, after exiting the script the variable remains with its initial value 1.
THanks for your time.
A shell script executes in its own shell, so you cannot affect the outer shell unless you source it. See this question for details of that discussion.
Consider the following script, which I will call Foo.sh.
#!/bin/bash
export HELLO=$(($HELLO+1))
Suppose in the outer shell, I define an environmental variable:
export HELLO=1
If I run the script like this, it run inside its own shell and will not affect the parent.
./Foo.sh
However, if I source it, it will just execute the commands in the current shell, and will achieve the desired affect.
. Foo.sh
echo $HELLO # prints 2
Your script can not change the environment of the calling process (shell), it merely inherits it.
So, if you export foo=bar, and then invoke sh (a new process) with your script, the script will see the value of $foo (which is "bar"), and it will be able to change its own copy of it – but that is not going to affect the environment of the parent process (where you exported the variable).
You can simply source your script in the original shell, i.e. run
source increment_script.sh
or
. increment_script.sh
and that will then change the value of the variable.
This is because sourceing a script avoids spawning a new shell (process).
Another trick is to have your script output the changed environment, and then eval that output, for example:
counter=$[counter+1]
echo "counter=$counter"
and then run that as
eval `increment_script.sh`

Setting an environment variable through a Perl script [duplicate]

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.

How to make declare in a Linux shell script?

I want to put below declare in a shell script: proxy_set
declare -x https_proxy="https://192.168.220.4:8080/"
And then I execute it like below.
$ ./proxy_set
But "export" shows nothing happened.
And in another way if I execute it like this:
$ source proxy_set
Then "export" shows it works!
My question is how can I make it work without additional "source" cmd?
Thanks!
You can't. Setting variables in the environment only affects the environment of that shell and any future children it spawns; there's no way to affect the parent shell. When you run it without the source (or .), a brand new shell is started up, then the variable is set in that shell's environment, and then that shell exits, taking its environment with it.
The source reads the commands and executes them within the current shell as if you had typed them.
So if you want to set environment variables in a script, you have to source it. Alternatively, you can have a command generate shell commands as output instead of running them, and then the parent can evaluate the output of the command. Things like ssh-agent use this approach.
Try just adding:
export https_proxy="https://192.168.220.4:8080/"
Then execute your script normally.

Resources