Can I set PERL5LIB in a separate script and call that script in other scripts? How do I do it? And how would it affect the script in which it is used?
Setting PERL5LIB at runtime will not affect Perl's search path. You need to export the variable before executing the interpreter.
Alternatively you can modify #INC at compile time (also possible to do in a separate script/module):
BEGIN { unshift #INC, "/path/to/dir" }
This is what the lib pragma does.
You'd do this via 'use lib' rather than manipulating the environment:
use lib '/home/perl5';
That could be in a separate file that you 'require' in.
PERL5INC is a shell environment variable, so you wouldn't set it inside your Perl program (normally) but instead specify it before invoking Perl. The below is a shell command where I've used PERL5LIB to instruct prove to find a Perl module residing in ~/OnePop:
$ PERL5LIB=~/OnePop prove -l t
... PERL5LIB is unset here ....
When a command is preceded by a variable assignment like this, the shell sets and exports the variable (PERL5LIB) to that command, but after that the variable will be unset again. You can also set the variable in the shell, so that all subsequent commands will inherit it.
$ export PERL5LIB=~/OnePop
...
$ prove -l t
... PERL5LIB continues to be set here ...
If you forget the export keyword in the above example (i.e. assigns the value using PERL5LIB=~/OnePop on a separate line) the variable will be set in the shell, but it will not be inherited by any commands you run (meaning that prove will not be able to see it).
Finally, if you wanted to set the environment PERL5LIB variable from inside a Perl program you'd have to write it like this:
$ENV{PERL5LIB} = glob("~/OnePop"); # glob() expands the tilde
system(qw( prove -l t ));
Though, as other have pointed out, if you want to specify the include path from inside Perl it is easier/better to use use lib $PATH.
PERL5INC is an environment variable. Environment variables are only inherited from parents to their children and can't (easily) be set the other way around. If you want to store extra search paths in an external file I suggest you make it a simple list of paths and write a simple loop to read each path from the file and manipulate #INC in the current process. If you want this to be done early at compile time you'll have to use a BEGIN {} block.
For example
BEGIN{
open(INCFILE,"<","my.inc.file") or die($!);
foreach(<INCFILE>){
push #INC,$_;
}
close(INCFILE);
}
Alternative to PERL5LIB:
You could instead install the latest version of Perl 5 available (in a non-system location, of course). After you have used a module file or done whatever is necessary to make the new perl and cpan executables visible to your shell, you can use cpan to install all the modules you need. I have sometimes done this for individual applications in a similar vein to using Python Virtual Environments.
Related
I am setting env variables using *.csh file to current terminal. When I use system("/bin/tcsh *.csh") in the perl script, the *csh file executing but not setting any env variables to current terminal.
When I use system("/bin/tcsh *.csh") in the perl script, the *csh file executing but not setting any env variables to current terminal.
sub veloce_env_setup_sub {
printf "\n\n\t -veloce_env_setup option enabled\n";
system("/bin/tcsh /proj/I2BZA1/users/ssudi/SCRIPTS/veloce_env/vlab_4p4p0/veloce_setup.csh");
}
Expected: env variables should set to current terminal after sourcing *.csh file.
Actual results: only prints are comming but not setting env variables to current terminal.
perldoc -q environment:
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 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.
In your code the problem appears twice:
system spawns tcsh, which runs a script that sets environment variables. These environment variables only exist within the tcsh process. When system returns (i.e. when tcsh exits), the environment of the child process is gone.
Even if you managed to modify the environment of the perl script (which you can do by assigning to %ENV), that wouldn't affect the parent shell that perl was started from.
This can now be done with Env::Modify.
use Env::Modify qw(:tcsh source);
sub veloce_env_setup_sub {
printf "\n\n\t -veloce_env_setup option enabled\n";
source("/proj/I2BZA1/users/ssudi/SCRIPTS/veloce_env/vlab_4p4p0/veloce_setup.csh");
}
The environment of a child process doesn't affect the environment of the parent process. That is, a process that you start doesn't change the environment of the thing that started it.
If you want to set up the environment for a Perl script, you have some options. Which one works best for you depends on what you are trying to do.
Set up the options inside Perl. Instead of using a shell program, do it all in Perl by setting values in the %ENV hash. This works well if you just need it for that program. It's likely that whatever you are doing in tcsh you can do it Perl.
Instead of calling the shell script from Perl, call your Perl program from the shell script. Now the shell script is the parent process and the child process (the Perl program) inherits the parent's environment.
#!tcsh
setenv SOME_VALUE foo
perl my_program
In a child process, you could print the environment and read that from the parent process. You'd parse it and convert it appropriately. This is what the Env::Modify module does, but I wouldn't want that as my first option.
You can't access environment variables in a process that have been set by a child process. It's a fundamental property of how processes work.
You can set %ENV{'your_choice'} = 'as you like'; inside Perl.
Sure, it looks like a little bit hartverdrahtet (yt), but it works great again. So the environmental is mental just inner the mind of top instanced script and closed and removed on closing it.
Another way is calling system("set VARIABLE=VALUE");
Here the variable lefts after closing until next reboot.
I have 2 versions of perl installed. perl v5.18.2 and v5.20.0 . But when I do perl -v I get perl v5.18.2. I don't need v5.18.2 at all. I need v5.20.0. How do I change the path to include v5.20.0 and not v5.18.2?
Here is my $PATH:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
v5.18.2 is installed at /usr/bin/perl and /usr/bin/perl5.18.2, and v5.20.0 at /root/perl5/perlbrew/perls/perl-5.20.0/bin/perl.
See the perlbrew documentation:
switch Permanently use the specified perl as default
perlbrew switch perl-5.20.0
If you haven't already, you will need to add source /root/perl5/perlbrew/etc/bashrc to your login script for this to work.
The following will add the desired build of Perl to the search path so that it's found first:
export PATH="/root/perl5/perlbrew/perls/perl-5.20.0/bin:$PATH"
You may add that to your login script to make this change permanent.
Note that you'll need to update the shebang (#!) lines of scripts installed with a different perl to the following:
#!/root/perl5/perlbrew/perls/perl-5.20.0/bin/perl
It looks like you have three copies of perl installed, as neither of the paths you mentioned are in the PATH variable yet your shell still finds one
There's no need for perlbrew. All you need to do is set your PATH variable on the command line
$ export PATH=/usr/bin/perl5.18.2:$PATH
If you want to make that change permanent then add the command to your profile file at ~/.profile
I want to source a shell script from within Perl and have the environment variables be available in Perl, but I'm not sure if there's an elegant way to do it. Obviously, using system() won't work since it runs in a forked process, and all environment changes will be lost. I think there's a CPAN module that can do it, but I prefer not to use external modules.
I've seen two solutions that would not work in my case:
Have a wrapper that calls the shell script, and then calls the Perl script. I do not know ahead of time which of my shell scripts I need to call.
Manually opening the shell script and scraping for arg=value pairs. This won't work either because the shell script is not a simple list of ARG=VALUE, but rather contain a bunch of conditionals, and variables can have different values depending on certain conditions.
sh -c "source script; env" should output the environment at the end of script as name=value pairs, which you then can parse from your perl script (as Perl is a language made for parsing, this should be easy).
You can do this by installing external module from CPAN which is Shell::Source
$env_path= Shell::Source->new(shell=>"tcsh",file=>"../path/to/file/temp.csh");
$env_path->inherit;
As perl creates its own instance while running on a shell, so we can not set environment path for the main shell as the perl's instance will be like sub shell of the main shell. Child can not set environment paths for parents.
Now till the perl's sub shell will run you'll be able to access all the paths present in temp.csh by using Shell::Source
I would like to do something like this:
chroot /mount-point /path/to/script $var1 $var 2
Will this work? Will the chrooted Perl script be passed on these 2 parameters?
If not, how to do this?
Otherwise, is there any way to simply do chroot in the script, and then start doing commands such as
perl script.pl $var1 $var2 etc?
As I understand it, simply writing them sequentially in bash will only get them executed after chroot is finished, and control is returned back to where I don't have perl installed (its a ramdisk running from PXE).
Chroot should handle this just fine. Just make sure that your perl script can find a Perl interpreter from the chroot context, that the Perl executable can find the shared libraries it needs, and that your variables, if they contain paths, have paths relative to the new root, not the old. You may want to compile a statically-linked perl executable, if that's easier for you than making copies of the required shared libraries in the chroot.
Or you can use Expect, which is a scripting language for interacting with input/output.
http://en.wikipedia.org/wiki/Expect
I have a bunch of Perl scripts that all run fine, yet need to have use Plibdata; up top.
I set up a cron job that runs (I get the confirmation email from root) and it spits back the following error message:
Can't locate Plibdata.pm in #INC (#INC contains: /install/lib /opt/perl58/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl58/lib/5.8.8 /opt/perl58/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl58/lib/site_perl/5.8.8 /opt/perl58/lib/site_perl .) at ./x line 5.
BEGIN failed--compilation aborted at ./x line 5.
Line 5 is... you guessed it.... use Plibdata;
I am also attempting to set the environment as such:
use lib "$ENV{CARSPATH}/install/lib";
so maybe if I found the location of this plibdata, I could explicitly direct it that way?
My cron commands will be executed using /usr/bin/sh says crontabs...
Any suggestions?
This script works from the command line.
You don't say what Plibdata is. You also don't state if this works at your command prompt. I assume that it does.
Try this:
perl -MPlibdata -e 1
Assuming that doesn't spit the same error, try this:
perl -MPlibdata -le 'print $INC{"Plibdata.pm"}'
That will tell you where. (It's probably in your PERL5LIB env var if this works.) Then you can just add the appropriate "use lib" to the directory Plibdata.pm is in.
Also, be sure you're using the same perl in both locations - command line ("which perl") and in the cron job (try "BEGIN { print $^X }" at the top of your script).
Cron uses a different user env than your env when logged in. Are you able to run the script from the command line? If so, just set your env variables inside the cron above your current commands.
Clearly, Plibdata.pm is not installed in the default module paths on your system:
/install/lib /opt/perl58/lib/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl58/lib/5.8.8 /opt/perl58/lib/site_perl/5.8.8/IA64.ARCHREV_0-thread-multi /opt/perl58/lib/site_perl/5.8.8 /opt/perl58/lib/site_perl
You have three choices:
Install Plibdata.pm in a known Perl system path (site_perl is the classic option).
Make the PERL5LIB shell environment (or the equivalent command line -I option for Perl) include the installation path of the module.
Use use lib in your script. Remember that the use lib action is done at compile time, so your variable in the path may not be initialised. Try using the variable in a BEGIN block like this:
my $env;
BEGIN {
$env = $ENV{CARSPATH};
}
use lib "$env/install/lib";
Running your program from a wrapper script as others have suggested is probably my preferred method, but there may be a few other solutions:
If you're using a modern cron you may be able to do something like this in your crontab entry:
* * * * * CARSPATH=/opt/carsi x
replacing the asterisks with the appropriate schedule designators.
This will set CARSPATH for the x process and allow the use lib statement that passes the environment variable to work.
You can also, depending on your shell and cron implementation, store your environment setup in a file and do something like:
* * * * * source specialenv.sh && x
Where specialenv.sh contains lines like (for bash)
export CARSPATH=/opt/carsi
You may also be able to set environment variables directly in the crontab, should you choose to do so.
cron does not setup an environment for you when it runs your code, so the environment variable $CARSPATH does not exist. I suggest only running shell scripts from cron, setting the environment inside of the shell script and then running the program you really wanted to run.
example wrapper script:
#!/bin/bash
source ~username/.bash_profile
cd ~username
./script.pl
If you are using ksh or sh you may need to say
#!/bin/sh
. ~username/.profile
cd ~username
./script.pl
Remember to replace username with your username on the system. Also, if the script is not in your home directory you will want to execute it with the path to it, not ./.
You say source, or period space, to load a given shell script in the current shell. You load it in the current shell so that any environment settings stay with the current shell.
~/.bash_profile, ~/.bashrc, ~/.profile, /etc/profile, etc. are all files that commonly hold your environment setup. Which one you are using depends heavily on your OS and who set it up.
Although its not an 'answer', I resolved this issue by using DBI instead of the Plibdata.
Which is kind of milky because now I will have to change a couple scripts around... ahhhhh I wish there was something I could do to make the Plibdata work
I'm still going to try Chas. Owens answer to see if that works
didn't work for me... "interpreter "/bin/bash" not found"maybe it would work with people who have that interpreter
* * * * * CARSPATH=/opt/carsi ./x
works